From b3ee5cb71c73bf943efe5334776e737a24508649 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 1 Oct 2013 13:34:13 -0700 Subject: [PATCH 0001/1866] Adds compress to README --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index 7c8222db..8650f13d 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ library. [dropwhile](#dropwhile)
[enumerate](#enumerate)
[cycle](#cycle)
+[compress](#compress)
[zip](#zip)
[chain](#chain)
[reverse](#reverse)
@@ -163,6 +164,21 @@ range instead of the shortest. because of that you have to return a `zip_get` +compress +-------- + +Yields only the values corresponding to true in the selectors iterable. +Terminates on the shortest sequence. + +Prints 2 6 +```c++ +vector ivec{1, 2, 3, 4, 5, 6}; +vector bvec{false, true, false, false, false, true}; +for (auto i : compress(ivec, bvec) { + cout << i << '\n'; +} +``` + chain ----- From 3b2d874653b0d7c4420709f837945b22c6fe5db0 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Wed, 2 Oct 2013 00:58:22 -0400 Subject: [PATCH 0002/1866] zip_iter now derefs to a tuple of the iterators elements, not a tuple of iterators --- tests/testzip.cpp | 50 +++++++++++++++++++++++------------------------ zip.hpp | 11 ++++++----- 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/tests/testzip.cpp b/tests/testzip.cpp index f3cd6e39..6f635a97 100644 --- a/tests/testzip.cpp +++ b/tests/testzip.cpp @@ -14,15 +14,15 @@ int main() { std::vector svec{"hello", "good day", "goodbye"}; for (auto e : zip(ivec, svec)) { - auto &i = iter::zip_get<0>(e); + auto &i = std::get<0>(e); std::cout << i << std::endl; i = 69; - std::cout << iter::zip_get<1>(e) << std::endl; + std::cout << std::get<1>(e) << std::endl; } for (auto e : zip(ivec, svec)) { - std::cout << iter::zip_get<0>(e) << std::endl; - std::cout << iter::zip_get<1>(e) << std::endl; + std::cout << std::get<0>(e) << std::endl; + std::cout << std::get<1>(e) << std::endl; } } //Aaron's test @@ -33,40 +33,40 @@ int main() { 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 << iter::zip_get<0>(e) << " " - << iter::zip_get<1>(e) << " " - << iter::zip_get<2>(e) << " " - << iter::zip_get<3>(e) << std::endl; - iter::zip_get<1>(e)=2.2f; //modify the float array + 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) << " " - << iter::zip_get<1>(e) << " " - << iter::zip_get<2>(e) << " " - << iter::zip_get<3>(e) << std::endl; + std::cout << std::get<0>(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 << iter::zip_get<0>(e) << " " - << iter::zip_get<1>(e) << " " - << iter::zip_get<2>(e) << " " - << iter::zip_get<3>(e) << std::endl; + std::cout << std::get<0>(e) << " " + << std::get<1>(e) << " " + << std::get<2>(e) << " " + << std::get<3>(e) << std::endl; } std::cout<(e) << " " - << iter::zip_get<1>(e) << " " - << iter::zip_get<2>(e) << " " - << iter::zip_get<3>(e) << std::endl; + std::cout << std::get<0>(e) << " " + << std::get<1>(e) << " " + << std::get<2>(e) << " " + << std::get<3>(e) << std::endl; }//both should print nothing std::cout<(e) << " " - << iter::zip_get<1>(e) << " " - << iter::zip_get<2>(e) << " " - << iter::zip_get<3>(e) << std::endl; + std::cout << std::get<0>(e) << " " + << std::get<1>(e) << " " + << std::get<2>(e) << " " + << std::get<3>(e) << std::endl; } std::cout<(containers.end()...); return iterator_range(begin,end); } - template + /*template auto zip_get(Tuple & t) ->decltype(*std::get(t))& { return *std::get(t); } + */ template struct zip_iter { @@ -33,9 +34,9 @@ namespace iter { zip_iter(const First & f, const Second & s) : iter1(f),iter2(s) { } - auto operator*() -> decltype(std::make_tuple(iter1,iter2)) + auto operator*() -> decltype(std::tie(*iter1,*iter2)) { - return std::make_tuple(iter1,iter2); + return std::tie(*iter1,*iter2); } zip_iter & operator++() { ++iter1; @@ -56,7 +57,7 @@ namespace iter { public: using Elem_t = decltype(*iter); using tuple_t = - decltype(std::tuple_cat(std::make_tuple(iter),*inner_iter)); + decltype(std::tuple_cat(std::tie(*iter),*inner_iter)); zip_iter(const First & f, const Rest & ... rest) : iter(f), @@ -66,7 +67,7 @@ namespace iter { tuple_t operator*() { - return std::tuple_cat(std::make_tuple(iter),*inner_iter); + return std::tuple_cat(std::tie(*iter),*inner_iter); } zip_iter & operator++() { ++iter; From c971b3be83168caf68fd37c3d5c6fcd85807fe3a Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Wed, 2 Oct 2013 01:16:17 -0400 Subject: [PATCH 0003/1866] zip_longest_iter returns tuple of boost::optional --- tests/testzip_longest.cpp | 6 +++--- zip_longest.hpp | 15 ++++++++++----- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/tests/testzip_longest.cpp b/tests/testzip_longest.cpp index d58fd476..e2fb8aab 100644 --- a/tests/testzip_longest.cpp +++ b/tests/testzip_longest.cpp @@ -11,7 +11,7 @@ using iter::zip_longest; template std::ostream & operator<<(std::ostream & o, const boost::optional & opt) { if (opt) { - std::cout << **opt << std::endl; + std::cout << *opt << std::endl; } else { std::cout << "Object disengaged of type " << typeid(T).name() << std::endl; @@ -43,9 +43,9 @@ int main() { << 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::get<1>(e)=2.2f; //modify the float array } - std::cout<(e) << std::get<1>(e) diff --git a/zip_longest.hpp b/zip_longest.hpp index b9db743c..b546abe3 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -38,11 +38,12 @@ namespace iter { zip_longest_iter(Container & c) : begin(c.begin()),end(c.end()) {} - std::tuple> operator*() + std::tuple())>> + operator*() { return std::make_tuple(begin != end ? - boost::optional(begin) - : boost::optional()); + boost::optional())>(*begin) + : boost::optional())>()); } zip_longest_iter & operator++() { if(begin!=end)++begin; @@ -64,7 +65,9 @@ namespace iter { public: using Elem_t = decltype(*begin); using tuple_t = - decltype(std::tuple_cat(std::tuple>(),*inner_iter)); + decltype(std::tuple_cat( + std::tuple>(), + *inner_iter)); zip_longest_iter(Container & c, Containers & ... containers) : begin(c.begin()), @@ -75,7 +78,9 @@ namespace iter { tuple_t operator*() { - return std::tuple_cat(std::make_tuple(begin != end ?boost::optional(begin):boost::optional()),*inner_iter); + return std::tuple_cat(std::make_tuple(begin != end + ?boost::optional(*begin) + :boost::optional()),*inner_iter); } zip_longest_iter & operator++() { if (begin != end) ++begin; From ccb1c8d22f1e7ed74a730b5027d9d5cd0ba7e48d Mon Sep 17 00:00:00 2001 From: aaronjosephs Date: Wed, 2 Oct 2013 01:24:52 -0400 Subject: [PATCH 0004/1866] Readme updated for improved zip and zip_longest --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 8650f13d..16b71a4b 100644 --- a/README.md +++ b/README.md @@ -137,8 +137,8 @@ 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 iterators to -those containers. +When you dereference an iterator to "zipped" range you get a tuple of whatever elements +the iterators were holding. Example usage: ```c++ @@ -148,20 +148,20 @@ vector s{"i","like","apples","alot","dude"}; array d{{1.2,1.2,1.2,1.2,1.2}}; for (auto e : zip(i,f,s,d)) { - cout << zip_get<0>(e) << ' ' - << zip_get<1>(e) << ' ' - << zip_get<2>(e) << ' ' - << zip_get<3>(e) << '\n'; - zip_get<1>(e)=2.2f; // modify the float array + cout << std::get<0>(e) << ' ' + << std::get<1>(e) << ' ' + << std::get<2>(e) << ' ' + << std::get<3>(e) << '\n'; + std::get<1>(e)=2.2f; // modify the float array } ``` -`iter::zip_get` is used to readably dereference the iterators yielded +~~`iter::zip_get` is used to readably dereference the iterators yielded~~ a `zip_longest` also exists where the range terminates on the longest range instead of the shortest. because of that you have to return a -`boost::optional` (`std::optional` when it is released) and cannot use -`zip_get` +`boost::optional` where `T` is whatever type the iterator dereferenced +to (`std::optional` when it is released, if ever) compress From 3dec5d2a089db083ec434a9367fcae6efd41ff94 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 2 Oct 2013 02:37:43 -0700 Subject: [PATCH 0005/1866] Adds SConstruct and adds *.o to .gitignore I haven't used SCons all that much, but it's implicit dependency checking on header files is extremely useful. --- tests/.gitignore | 1 + tests/SConstruct | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 tests/SConstruct diff --git a/tests/.gitignore b/tests/.gitignore index 8f7d5db6..b07f3462 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,3 +1,4 @@ +*.o testchain testcycle testenumerate diff --git a/tests/SConstruct b/tests/SConstruct new file mode 100644 index 00000000..d06bfecd --- /dev/null +++ b/tests/SConstruct @@ -0,0 +1,27 @@ +progs = Split( ''' + cycle + enumerate + range + zip + slice + reverse + filter + repeat + takewhile + dropwhile + zip_longest + product + permutations + compress + combinations_with_replacement + combinations + powerset + ''') + +cxx_flags = '-Wall -Wextra -pedantic -std=c++11' + +for p in progs: + Program(target='test{0}'.format(p), source='test{0}.cpp'.format(p), + CXXFLAGS=cxx_flags, CPPPATH='..', CXX='clang++') + + From c23441defdd515597fe5915ed55f6090b67a6867 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Wed, 2 Oct 2013 15:44:51 -0400 Subject: [PATCH 0006/1866] started to do moving section --- iter_ideas.txt | 3 +- itertools.hpp | 1 + moving_section.hpp | 57 ++++++++++++++++++++++++++++++++++++ tests/Makefile | 3 +- tests/testmoving_section.cpp | 16 ++++++++++ 5 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 moving_section.hpp create mode 100644 tests/testmoving_section.cpp diff --git a/iter_ideas.txt b/iter_ideas.txt index 7c68e9c1..be6d2b9c 100644 --- a/iter_ideas.txt +++ b/iter_ideas.txt @@ -1,4 +1,5 @@ -x at a time iterator. Lets say you have a list +movingsection(Container & container,size_t section_size); +Lets say you have a list [1,2,3,4,5,6,7,8] and you want to iterate over 3 elements at a time. You could create three iterators and incrment them simulatneously, or do something like this. diff --git a/itertools.hpp b/itertools.hpp index 20119bb8..6e395e08 100644 --- a/itertools.hpp +++ b/itertools.hpp @@ -24,6 +24,7 @@ #include "zip.hpp" #include "zip_longest.hpp" #include "powerset.hpp" +#include "moving_section.hpp" //not sure if should include "iterator_range.hpp" //since it's already in everything diff --git a/moving_section.hpp b/moving_section.hpp new file mode 100644 index 00000000..bf05c404 --- /dev/null +++ b/moving_section.hpp @@ -0,0 +1,57 @@ +#ifndef MOVING_SECTION_HPP +#define MOVING_SECTION_HPP + +#include "iterator_range.hpp" +#include +#include + +namespace iter { + template + struct moving_section_iter; + template + iterator_range> + moving_section(Container & container, size_t s) { + auto begin = moving_section_iter(container,s); + auto end = moving_section_iter(container); + return iterator_range>(begin,end); + } + + template + struct moving_section_iter { + Container & container; + using Iterator = decltype(container.begin()); + std::vector section; + size_t section_size = 0; + moving_section_iter(Container & c, size_t s) : + container(c),section_size(s) { + for (size_t i = 0; i < section_size; ++i) + section.push_back(container.begin()+i); + } + moving_section_iter(Container & c) : container(c) + //creates the end iterator + { + section.push_back(container.end()); + } + + moving_section_iter & operator++() { + for (auto & iter : section) { + ++iter; + } + return *this; + //std::for_each(section.begin(),section.end(),[](Iterator & i){++i;}); + } + bool operator!=(const moving_section_iter & rhs) { + return this->section.back() != rhs.section.back(); + } + auto operator*() -> std::vector + { + std::vector vec(section.front(),section.back()+1); + //for (auto iter : section) { + // vec.push_back(*iter); + //} + return vec; + } + }; +} + +#endif //MOVING_SECTION_HPP diff --git a/tests/Makefile b/tests/Makefile index 83c3d7ce..7fadaf98 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -30,7 +30,8 @@ TESTS = \ testcompress \ testcombinations_with_replacement \ testcombinations \ - testpowerset + testpowerset \ + testmoving_section all: $(TESTS) diff --git a/tests/testmoving_section.cpp b/tests/testmoving_section.cpp new file mode 100644 index 00000000..65ce754f --- /dev/null +++ b/tests/testmoving_section.cpp @@ -0,0 +1,16 @@ +#include "moving_section.hpp" +#include +#include +using iter::moving_section; +int main() { + std::vector v = {1,2,3,4,5,6,7,8,9}; + for (auto sec : moving_section(v,4)) { + /* + for (auto & i : sec) { + std::cout << i << " "; + } + */ + std::cout << std::endl; + } + return 0; +} From 09e20368bd278bb35641402b32ec7ba9261f7050 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Wed, 2 Oct 2013 19:44:49 -0400 Subject: [PATCH 0007/1866] Test moving section working with reference wrapper, it has to be that way as vector cannot store references --- moving_section.hpp | 13 ++++++++----- tests/.gitignore | 1 + tests/testmoving_section.cpp | 5 ++--- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/moving_section.hpp b/moving_section.hpp index bf05c404..35b940bf 100644 --- a/moving_section.hpp +++ b/moving_section.hpp @@ -4,6 +4,8 @@ #include "iterator_range.hpp" #include #include +#include +#include namespace iter { template @@ -43,12 +45,13 @@ namespace iter { bool operator!=(const moving_section_iter & rhs) { return this->section.back() != rhs.section.back(); } - auto operator*() -> std::vector + using Deref_type = std::vector())>::type>>; + Deref_type operator*() { - std::vector vec(section.front(),section.back()+1); - //for (auto iter : section) { - // vec.push_back(*iter); - //} + Deref_type vec; + for (auto i : section) { + vec.push_back(*i); + } return vec; } }; diff --git a/tests/.gitignore b/tests/.gitignore index b07f3462..5db5fc20 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -17,3 +17,4 @@ testcombinations_with_replacement testtakewhile testcombinations testpowerset +testmoving_section diff --git a/tests/testmoving_section.cpp b/tests/testmoving_section.cpp index 65ce754f..3faf21e7 100644 --- a/tests/testmoving_section.cpp +++ b/tests/testmoving_section.cpp @@ -5,11 +5,10 @@ using iter::moving_section; int main() { std::vector v = {1,2,3,4,5,6,7,8,9}; for (auto sec : moving_section(v,4)) { - /* - for (auto & i : sec) { + for (auto i : sec) { std::cout << i << " "; + i.get() = 90; } - */ std::cout << std::endl; } return 0; From 8f0e0ed06bdc8077e7950a91d1b5a701c4a897c9 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Wed, 2 Oct 2013 17:06:17 -0700 Subject: [PATCH 0008/1866] Update LICENSE.md --- LICENSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.md b/LICENSE.md index 1d6598bb..3b340456 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,4 +1,4 @@ -Copyright (c) {{year}}, {{fullname}} +Copyright (c) 2013, Ryan Haining, Aaron Josephs All rights reserved. Redistribution and use in source and binary forms, with or without modification, From 433b6ef05c23f73f43ae25ce86a8b1e22b8e672d Mon Sep 17 00:00:00 2001 From: aaronjosephs Date: Thu, 3 Oct 2013 02:38:18 -0400 Subject: [PATCH 0009/1866] Updated README for moving_section --- README.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/README.md b/README.md index 16b71a4b..598465c7 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ library. [chain](#chain)
[reverse](#reverse)
[slice](#slice)
+[moving_section](#moving_section)
##### Combinatoric fuctions [product](#product)
@@ -285,3 +286,36 @@ for (auto v : powerset(vec)) { std::cout << std::endl; } ``` + +moving_section +------------- + +Takes a section from a range and increments the whole section. + +Example: +`[1, 2, 3, 4, 5, 6, 7, 8, 9]` + +take a section of size 4, output is: +``` +1 2 3 4 +2 3 4 5 +3 4 5 6 +4 5 6 7 +5 6 7 8 +6 7 8 9 +``` + +Example Usage: +```c++ +std::vector v = {1,2,3,4,5,6,7,8,9}; +for (auto sec : moving_section(v,4)) { + for (auto i : sec) { + std::cout << i << " "; + i.get() = 90; + //has to be accessed with get if you want to store references + //because it is stored in a reference_wrapper (std::vector + //cannot hold references) + } + std::cout << std::endl; +} +``` From b7630230f8c6509e89704d2b96337394005aee25 Mon Sep 17 00:00:00 2001 From: aaronjosephs Date: Thu, 3 Oct 2013 02:40:26 -0400 Subject: [PATCH 0010/1866] moving_section put in wrong spot --- README.md | 66 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 598465c7..b57e1407 100644 --- a/README.md +++ b/README.md @@ -221,6 +221,39 @@ for (auto i : slice(a,0,15,3)) { } ``` +moving_section +------------- + +Takes a section from a range and increments the whole section. + +Example: +`[1, 2, 3, 4, 5, 6, 7, 8, 9]` + +take a section of size 4, output is: +``` +1 2 3 4 +2 3 4 5 +3 4 5 6 +4 5 6 7 +5 6 7 8 +6 7 8 9 +``` + +Example Usage: +```c++ +std::vector v = {1,2,3,4,5,6,7,8,9}; +for (auto sec : moving_section(v,4)) { + for (auto i : sec) { + std::cout << i << " "; + i.get() = 90; + //has to be accessed with get if you want to store references + //because it is stored in a reference_wrapper (std::vector + //cannot hold references) + } + std::cout << std::endl; +} +``` + product ------ @@ -287,35 +320,4 @@ for (auto v : powerset(vec)) { } ``` -moving_section -------------- - -Takes a section from a range and increments the whole section. - -Example: -`[1, 2, 3, 4, 5, 6, 7, 8, 9]` - -take a section of size 4, output is: -``` -1 2 3 4 -2 3 4 5 -3 4 5 6 -4 5 6 7 -5 6 7 8 -6 7 8 9 -``` - -Example Usage: -```c++ -std::vector v = {1,2,3,4,5,6,7,8,9}; -for (auto sec : moving_section(v,4)) { - for (auto i : sec) { - std::cout << i << " "; - i.get() = 90; - //has to be accessed with get if you want to store references - //because it is stored in a reference_wrapper (std::vector - //cannot hold references) - } - std::cout << std::endl; -} -``` + From 37fca81bb6d76c4bb6a2798fb491b5b12fbcf8b7 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Thu, 3 Oct 2013 10:42:21 -0700 Subject: [PATCH 0011/1866] Adds compress to itertools.hpp --- itertools.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/itertools.hpp b/itertools.hpp index 6e395e08..13b5c57a 100644 --- a/itertools.hpp +++ b/itertools.hpp @@ -8,6 +8,7 @@ #include "chain.hpp" #include "combinations_with_replacement.hpp" #include "combinations.hpp" +#include "compress.hpp" #include "cycle.hpp" #include "dropwhile.hpp" #include "enumerate.hpp" From 094b1d366d7b60c0d18f6c18e25339149a63112d Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Thu, 3 Oct 2013 12:25:25 -0700 Subject: [PATCH 0012/1866] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index b57e1407..ca6752c2 100644 --- a/README.md +++ b/README.md @@ -157,7 +157,6 @@ for (auto e : zip(i,f,s,d)) { } ``` -~~`iter::zip_get` is used to readably dereference the iterators yielded~~ a `zip_longest` also exists where the range terminates on the longest range instead of the shortest. because of that you have to return a From 9e21aa135e079ec935e1b767b06924676dd12718 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Thu, 3 Oct 2013 17:25:42 -0400 Subject: [PATCH 0013/1866] removed extra include from itertools.hpp --- itertools.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/itertools.hpp b/itertools.hpp index 13b5c57a..fe40a3e3 100644 --- a/itertools.hpp +++ b/itertools.hpp @@ -5,7 +5,6 @@ #include "reverse.hpp" #include "slice.hpp" #include "chain.hpp" -#include "chain.hpp" #include "combinations_with_replacement.hpp" #include "combinations.hpp" #include "compress.hpp" From ec8adef238017f33b58db964e4ac50658affb0cb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 4 Oct 2013 15:47:14 -0700 Subject: [PATCH 0014/1866] Adds simple imap Only works on a single iterator. --- imap.hpp | 99 ++++++++++++++++++++++++++++++++++++++++++++++ tests/SConstruct | 2 + tests/testimap.cpp | 14 +++++++ 3 files changed, 115 insertions(+) create mode 100644 imap.hpp create mode 100644 tests/testimap.cpp diff --git a/imap.hpp b/imap.hpp new file mode 100644 index 00000000..8d94e726 --- /dev/null +++ b/imap.hpp @@ -0,0 +1,99 @@ +#ifndef IMAP__H__ +#define IMAP__H__ + +#include +#include + +namespace iter { + + //Forward declarations of IMap and imap + template + class IMap; + + template + IMap imap(MapFunc, Container &); + + template + class IMap { + // The imap function is the only thing allowed to create a IMap + friend IMap imap(MapFunc, Container &); + + // Type of the Container::Iterator, but since the name of that + // iterator can be anything, we have to grab it with this + using contained_iter_type = + decltype(std::declval().begin()); + + // The type returned when dereferencing the Container::Iterator + using contained_iter_ret = + decltype(std::declval().operator*()); + + private: + Container & container; + MapFunc map_func; + + // Value constructor for use only in the imap function + IMap(MapFunc map_func, Container & container) : + container(container), + map_func(map_func) + { } + IMap () = delete; + IMap & operator=(const IMap &) = delete; + + public: + IMap (const IMap &) = default; + + class Iterator { + private: + contained_iter_type sub_iter; + const contained_iter_type sub_end; + MapFunc map_func; + + public: + Iterator (contained_iter_type iter, + contained_iter_type end, + MapFunc map_func) : + sub_iter(iter), + sub_end(end), + map_func(map_func) + { } + + auto operator*() const -> decltype(map_func(*this->sub_iter)) { + return map_func(*this->sub_iter); + } + + Iterator & operator++() { + ++this->sub_iter; + return *this; + } + + bool operator!=(const Iterator & other) const { + return this->sub_iter != other.sub_iter; + } + }; + + Iterator begin() const { + return Iterator( + this->container.begin(), + this->container.end(), + this->map_func); + } + + Iterator end() const { + return Iterator( + this->container.end(), + this->container.end(), + this->map_func); + } + + }; + + // Helper function to instantiate a IMap + template + IMap imap( + MapFunc map_func, Container & container) { + return IMap(map_func, container); + } + +} + +#endif //ifndef IMAP__H__ diff --git a/tests/SConstruct b/tests/SConstruct index d06bfecd..06332784 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -16,6 +16,8 @@ progs = Split( ''' combinations_with_replacement combinations powerset + moving_section + imap ''') cxx_flags = '-Wall -Wextra -pedantic -std=c++11' diff --git a/tests/testimap.cpp b/tests/testimap.cpp new file mode 100644 index 00000000..e764d9fb --- /dev/null +++ b/tests/testimap.cpp @@ -0,0 +1,14 @@ +#include + +#include +#include + +using iter::imap; + +int main() { + std::vector vec= {1, 2, 3, 4, 5, 6}; + for (auto i : imap([] (int x) { return x * x; }, vec)) { + std::cout << i << '\n'; + } + return 0; +} From aa6ae78167d78ce0e6fd1cd2fe58adf0da89c562 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 4 Oct 2013 17:56:11 -0700 Subject: [PATCH 0015/1866] Starts to covert to variadic imap --- imap.hpp | 106 ++++++++++++++++++++++++++++----------------- tests/testimap.cpp | 5 ++- 2 files changed, 70 insertions(+), 41 deletions(-) diff --git a/imap.hpp b/imap.hpp index 8d94e726..d5570539 100644 --- a/imap.hpp +++ b/imap.hpp @@ -1,40 +1,77 @@ #ifndef IMAP__H__ #define IMAP__H__ +#include "zip.hpp" + #include #include namespace iter { + // implementation details, users never invoke these directly + namespace detail + { + template + struct call_impl + { + static void call(F f, Tuple && t) + { + call_impl::call(f, std::forward(t)); + } + }; + + template + struct call_impl + { + static void call(F f, Tuple && t) + { + f(std::get(std::forward(t))...); + } + }; + + // user invokes this + template + void call(F f, Tuple && t) + { + typedef typename std::decay::type ttype; + call_impl::value, + std::tuple_size::value>::call(f, + std::forward(t)); + } + } + //Forward declarations of IMap and imap - template + template class IMap; - template - IMap imap(MapFunc, Container &); + template + IMap imap(MapFunc, Containers &...); - template + template class IMap { // The imap function is the only thing allowed to create a IMap - friend IMap imap(MapFunc, Container &); + friend IMap imap(MapFunc, Containers & ...); - // Type of the Container::Iterator, but since the name of that - // iterator can be anything, we have to grab it with this - using contained_iter_type = - decltype(std::declval().begin()); + // The type returned when dereferencing the Containers...::Iterator + using Zipped = iterator_range>; - // The type returned when dereferencing the Container::Iterator - using contained_iter_ret = - decltype(std::declval().operator*()); + using ZippedIterType = decltype(std::declval().begin()); private: - Container & container; MapFunc map_func; + Zipped zipped; // Value constructor for use only in the imap function - IMap(MapFunc map_func, Container & container) : - container(container), - map_func(map_func) + IMap(MapFunc map_func, Containers & ... containers) : + map_func(map_func), + zipped(zip(containers...)) { } IMap () = delete; IMap & operator=(const IMap &) = delete; @@ -44,54 +81,45 @@ namespace iter { class Iterator { private: - contained_iter_type sub_iter; - const contained_iter_type sub_end; MapFunc map_func; + ZippedIterType zipiter; public: - Iterator (contained_iter_type iter, - contained_iter_type end, - MapFunc map_func) : - sub_iter(iter), - sub_end(end), + Iterator (MapFunc map_func, ZippedIterType zipiter) : + zipiter(zipiter), map_func(map_func) { } - auto operator*() const -> decltype(map_func(*this->sub_iter)) { - return map_func(*this->sub_iter); + auto operator*() const -> + decltype(detail::call(map_func, *this->zipter)) { + return detail::call(map_func, *zipiter); } Iterator & operator++() { - ++this->sub_iter; + ++this->zipiter; return *this; } bool operator!=(const Iterator & other) const { - return this->sub_iter != other.sub_iter; + return this->zipiter != other.zipiter; } }; Iterator begin() const { - return Iterator( - this->container.begin(), - this->container.end(), - this->map_func); + return Iterator(this->map_func, this->zipped.begin()); } Iterator end() const { - return Iterator( - this->container.end(), - this->container.end(), - this->map_func); + return Iterator(this->map_func, this->zipped.end()); } }; // Helper function to instantiate a IMap - template - IMap imap( - MapFunc map_func, Container & container) { - return IMap(map_func, container); + template + IMap imap( + MapFunc map_func, Containers & ... containers) { + return IMap(map_func, containers...); } } diff --git a/tests/testimap.cpp b/tests/testimap.cpp index e764d9fb..a2b74f5b 100644 --- a/tests/testimap.cpp +++ b/tests/testimap.cpp @@ -6,8 +6,9 @@ using iter::imap; int main() { - std::vector vec= {1, 2, 3, 4, 5, 6}; - for (auto i : imap([] (int x) { return x * x; }, vec)) { + 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'; } return 0; From 89f7303e4752c56669b9fb50fd2310c24c5c8b4a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 4 Oct 2013 22:27:21 -0700 Subject: [PATCH 0016/1866] Closer to a working variadic imap --- imap.hpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/imap.hpp b/imap.hpp index d5570539..fb345e76 100644 --- a/imap.hpp +++ b/imap.hpp @@ -60,7 +60,9 @@ namespace iter { friend IMap imap(MapFunc, Containers & ...); // The type returned when dereferencing the Containers...::Iterator - using Zipped = iterator_range>; + // XXX depends on zip using iterator_range. would be nice if it didn't + using Zipped = + iterator_range().begin())...>>; using ZippedIterType = decltype(std::declval().begin()); @@ -86,13 +88,14 @@ namespace iter { public: Iterator (MapFunc map_func, ZippedIterType zipiter) : - zipiter(zipiter), - map_func(map_func) + map_func(map_func), + zipiter(zipiter) { } auto operator*() const -> - decltype(detail::call(map_func, *this->zipter)) { - return detail::call(map_func, *zipiter); + decltype(map_func(*this->zipiter)) + { + return detail::call(this->map_func, *this->zipiter); } Iterator & operator++() { From a46fc449dc5db94f528ad037bf5a8934251342be Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Fri, 4 Oct 2013 22:55:12 -0400 Subject: [PATCH 0017/1866] bullshit fix for imap --- imap.hpp | 9 +++++---- zip.hpp | 1 - 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/imap.hpp b/imap.hpp index fb345e76..9fb1999a 100644 --- a/imap.hpp +++ b/imap.hpp @@ -65,6 +65,7 @@ namespace iter { iterator_range().begin())...>>; using ZippedIterType = decltype(std::declval().begin()); + //typename std::remove_const().begin())>::type; private: MapFunc map_func; @@ -84,7 +85,7 @@ namespace iter { class Iterator { private: MapFunc map_func; - ZippedIterType zipiter; + mutable ZippedIterType zipiter; public: Iterator (MapFunc map_func, ZippedIterType zipiter) : @@ -92,10 +93,10 @@ namespace iter { zipiter(zipiter) { } - auto operator*() const -> - decltype(map_func(*this->zipiter)) + auto operator*() const -> + decltype(detail::call(this->map_func, *(this->zipiter))) { - return detail::call(this->map_func, *this->zipiter); + return detail::call(this->map_func, *(this->zipiter)); } Iterator & operator++() { diff --git a/zip.hpp b/zip.hpp index 52681dcb..a9286e97 100644 --- a/zip.hpp +++ b/zip.hpp @@ -63,7 +63,6 @@ namespace iter { iter(f), inner_iter(rest...) {} - //this is for returning a tuple of iterators tuple_t operator*() { From 4eea483e07354e000e0526238030d39424606580 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 4 Oct 2013 23:12:07 -0700 Subject: [PATCH 0018/1866] Adds return type to detail::call --- imap.hpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/imap.hpp b/imap.hpp index 9fb1999a..18c1a0d8 100644 --- a/imap.hpp +++ b/imap.hpp @@ -14,9 +14,9 @@ namespace iter { template struct call_impl { - static void call(F f, Tuple && t) + static auto call(F f, Tuple && t) -> decltype(f(t)) { - call_impl struct call_impl { - static void call(F f, Tuple && t) + static auto call(F f, Tuple && t) -> decltype(f(t)) { - f(std::get(std::forward(t))...); + return f(std::get(std::forward(t))...); } }; // user invokes this template - void call(F f, Tuple && t) + auto call(F f, Tuple && t) -> decltype(f(t)) { typedef typename std::decay::type ttype; - call_impl::value, - std::tuple_size::value>::call(f, - std::forward(t)); + std::tuple_size::value>::call(f,std::forward(t)); } } From 6bdc0c3ac15fe5bca5f9005f9f0ae0e8bf2e7294 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Fri, 4 Oct 2013 23:23:23 -0400 Subject: [PATCH 0019/1866] imap fixed with crazy delctypes --- imap.hpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/imap.hpp b/imap.hpp index 18c1a0d8..6de22b48 100644 --- a/imap.hpp +++ b/imap.hpp @@ -14,7 +14,13 @@ namespace iter { template struct call_impl { - static auto call(F f, Tuple && t) -> decltype(f(t)) + static auto call(F f, Tuple && t) -> + decltype(call_impl::call(f, std::forward(t))) { return call_impl struct call_impl { - static auto call(F f, Tuple && t) -> decltype(f(t)) + static auto call(F f, Tuple && t) -> + decltype(f(std::get(std::forward(t))...)) { return f(std::get(std::forward(t))...); } @@ -36,7 +43,12 @@ namespace iter { // user invokes this template - auto call(F f, Tuple && t) -> decltype(f(t)) + auto call(F f, Tuple && t) -> + decltype(call_impl::type>::value, + std::tuple_size::type>::value> + ::call(f,std::forward(t))) { typedef typename std::decay::type ttype; return call_impl Date: Fri, 4 Oct 2013 23:48:30 -0700 Subject: [PATCH 0020/1866] Adds citation --- imap.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/imap.hpp b/imap.hpp index 6de22b48..19239cdc 100644 --- a/imap.hpp +++ b/imap.hpp @@ -8,6 +8,7 @@ namespace iter { + // modified from http://stackoverflow.com/questions/10766112/ // implementation details, users never invoke these directly namespace detail { From b66271f3d745f53c191831d36b0e2d479d2af031 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 4 Oct 2013 23:56:54 -0700 Subject: [PATCH 0021/1866] Adds tests for imap --- tests/testimap.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/testimap.cpp b/tests/testimap.cpp index a2b74f5b..6f4e6f1f 100644 --- a/tests/testimap.cpp +++ b/tests/testimap.cpp @@ -11,5 +11,16 @@ int main() { 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'; + } + return 0; } From d4298b55a1b00f613360480ef07d78860ab2178a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 5 Oct 2013 00:03:47 -0700 Subject: [PATCH 0022/1866] changes to range --- range.hpp | 54 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/range.hpp b/range.hpp index 265d65e1..0415c71c 100644 --- a/range.hpp +++ b/range.hpp @@ -22,16 +22,19 @@ namespace iter { // Thrown when step 0 occurs class RangeException : public std::exception { virtual const char *what() const throw() { - return "range() step argument must not be zero"; + return "Range() step argument must not be zero"; } }; - class range { + template + class Range { private: const int start; const int stop; const int step; void step_check() const throw(RangeException); + + public: class Iterator { private: @@ -45,9 +48,17 @@ namespace iter { bool operator!=(const Iterator & other) const; }; - range(int stop); - range(int start, int stop); - range(int start, int stop, int step); + //Range + Range::Range(int stop) : + start(0), + stop(stop), + step(1) + { } + Range(int start, int stop); + Range(int start, int stop, int step); + + Range() = delete; + Range(const Range &) = default; Iterator begin() const; Iterator end() const; @@ -56,16 +67,16 @@ namespace iter { // definitions // Iterator subclass - range::Iterator::Iterator (int val, int step) : + Range::Iterator::Iterator (int val, int step) : value(val), step(step) { } - int range::Iterator::operator*() const { + int Range::Iterator::operator*() const { return this->value; } - range::Iterator & range::Iterator::operator++() { + Range::Iterator & Range::Iterator::operator++() { this->value += this->step; return *this; } @@ -74,31 +85,25 @@ namespace iter { // because exact comparison with the end isn't good enough for the purposes // of this Iterator. // There are two odd cases that need to be handled - // 1) The range is infinite, such as range (-1, 0, -1) which would go + // 1) The Range is infinite, such as Range (-1, 0, -1) which would go // forever down toward infinitely (theoretically). If this occurs, - // the range will instead effectively be empty - // 2) (stop - start) % step != 0. For example range(1, 10, 2). The + // the Range will instead effectively be empty + // 2) (stop - start) % step != 0. For example Range(1, 10, 2). The // iterator will never be exactly equal to the stop value. - bool range::Iterator::operator!=(const range::Iterator & other) const { + bool Range::Iterator::operator!=(const Range::Iterator & other) const { return !(this->step > 0 && this->value >= other.value) && !(this->step < 0 && this->value <= other.value); } - //Range - range::range(int stop) : - start(0), - stop(stop), - step(1) - { } - range::range(int start, int stop) : + Range::Range(int start, int stop) : start(start), stop(stop), step(1) { } - range::range(int start, int stop, int step) : + Range::Range(int start, int stop, int step) : start(start), stop(stop), step(step) @@ -106,20 +111,23 @@ namespace iter { this->step_check(); } - void range::step_check() const throw(RangeException) { + void Range::step_check() const throw(RangeException) { if (step == 0) { throw RangeException(); } } - range::Iterator range::begin() const { + Range::Iterator Range::begin() const { return Iterator(start, step); } - range::Iterator range::end() const { + Range::Iterator Range::end() const { return Iterator(stop, step); } } +template +Range range + #endif //ifndef __RANGE__H__ From aaea6b8658284b6894903c32ed58300715bc84e7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 5 Oct 2013 00:31:01 -0700 Subject: [PATCH 0023/1866] Templates range Templates range so it works with whatever the user wants. range(0.0, 10.0, 0.5) for example. --- range.hpp | 149 ++++++++++++++++++++++---------------------- tests/testrange.cpp | 5 ++ 2 files changed, 78 insertions(+), 76 deletions(-) diff --git a/range.hpp b/range.hpp index 0415c71c..2ccfb1e1 100644 --- a/range.hpp +++ b/range.hpp @@ -29,105 +29,102 @@ namespace iter { template class Range { private: - const int start; - const int stop; - const int step; - void step_check() const throw(RangeException); + const T start; + const T stop; + const T step; + void step_check() const throw(RangeException) { + if (step == 0) { + throw RangeException(); + } + } public: class Iterator { private: - int value; - const int step; + T value; + const T step; public: - Iterator (int val, int step); - - int operator*() const; - Iterator & operator++(); - bool operator!=(const Iterator & other) const; + Iterator(T val, T step) : + value(val), + step(step) + { } + + T operator*() const { + return this->value; + } + + Iterator & operator++() { + this->value += this->step; + return *this; + } + + // This operator would more accurately read as "in bounds" + // or "incomplete" because exact comparison with the end + // isn't good enough for the purposes of this Iterator. + // There are two odd cases that need to be handled + // + // 1) The Range is infinite, such as + // Range (-1, 0, -1) which would go forever down toward + // infinitely (theoretically). If this occurs, the Range + // will instead effectively be empty + // + // 2) (stop - start) % step != 0. For + // example Range(1, 10, 2). The iterator will never be + // exactly equal to the stop value. + bool operator!=(const Range::Iterator & other) const { + return !(this->step > 0 && this->value >= other.value) + && !(this->step < 0 && this->value <= other.value); + } }; - //Range - Range::Range(int stop) : + Range() = delete; + Range(const Range &) = default; + Range(T stop) : start(0), stop(stop), step(1) { } - Range(int start, int stop); - Range(int start, int stop, int step); - Range() = delete; - Range(const Range &) = default; + Range(T start, T stop) : + start(start), + stop(stop), + step(1) + { } - Iterator begin() const; - Iterator end() const; + Range(T start, T stop, T step) : + start(start), + stop(stop), + step(step) + { + this->step_check(); + } + + Iterator begin() const { + return Iterator(start, step); + } + + Iterator end() const { + return Iterator(stop, step); + } }; - // definitions - - // Iterator subclass - Range::Iterator::Iterator (int val, int step) : - value(val), - step(step) - { } - - int Range::Iterator::operator*() const { - return this->value; - } - - Range::Iterator & Range::Iterator::operator++() { - this->value += this->step; - return *this; - } - - // This operator would more accurately read as "in bounds" or "incomplete" - // because exact comparison with the end isn't good enough for the purposes - // of this Iterator. - // There are two odd cases that need to be handled - // 1) The Range is infinite, such as Range (-1, 0, -1) which would go - // forever down toward infinitely (theoretically). If this occurs, - // the Range will instead effectively be empty - // 2) (stop - start) % step != 0. For example Range(1, 10, 2). The - // iterator will never be exactly equal to the stop value. - bool Range::Iterator::operator!=(const Range::Iterator & other) const { - return !(this->step > 0 && this->value >= other.value) - && !(this->step < 0 && this->value <= other.value); - } - - Range::Range(int start, int stop) : - start(start), - stop(stop), - step(1) - { } - - Range::Range(int start, int stop, int step) : - start(start), - stop(stop), - step(step) - { - this->step_check(); - } - - void Range::step_check() const throw(RangeException) { - if (step == 0) { - throw RangeException(); - } + template + Range range(T stop) { + return Range(stop); } - Range::Iterator Range::begin() const { - return Iterator(start, step); + template + Range range(T start, T stop) { + return Range(start, stop); } - Range::Iterator Range::end() const { - return Iterator(stop, step); + template + Range range(T start, T stop, T step) { + return Range(start, stop, step); } - } -template -Range range - #endif //ifndef __RANGE__H__ diff --git a/tests/testrange.cpp b/tests/testrange.cpp index 158b3d14..5fa2a75e 100644 --- a/tests/testrange.cpp +++ b/tests/testrange.cpp @@ -34,6 +34,11 @@ int main() std::cout << i << std::endl; } + std::cout << "Tests with different types" << std::endl; + for(auto i : range(0.0, 10.0, 0.5)) { + 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)) { From ae5a92776808a41648f72257ac488b264cab30b4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 5 Oct 2013 01:53:20 -0700 Subject: [PATCH 0024/1866] Adds full SO citation to imap --- imap.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/imap.hpp b/imap.hpp index 19239cdc..5e156ff3 100644 --- a/imap.hpp +++ b/imap.hpp @@ -8,10 +8,13 @@ namespace iter { + // Everything in detail namespace // modified from http://stackoverflow.com/questions/10766112/ - // implementation details, users never invoke these directly + // Question by Thomas http://stackoverflow.com/users/115355/thomas + // Answer by Kerrek SB http://stackoverflow.com/users/596781/kerrek-sb namespace detail { + // implementation details, users never invoke these directly template struct call_impl { From d6c23a1af8113528fcef26f6c3d199530e670201 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 5 Oct 2013 02:07:28 -0700 Subject: [PATCH 0025/1866] Makes range ctors private and range()s friends --- range.hpp | 56 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/range.hpp b/range.hpp index 2ccfb1e1..edd48505 100644 --- a/range.hpp +++ b/range.hpp @@ -26,8 +26,22 @@ namespace iter { } }; + //Forward declarations of Enumerable and enumerate + template + class Range; + + template + Range range(T); + template + Range range(T, T); + template + Range range(T, T, T); + template class Range { + friend Range range(T); + friend Range range(T, T); + friend Range range(T, T, T); private: const T start; const T stop; @@ -38,8 +52,29 @@ namespace iter { } } + Range(T stop) : + start(0), + stop(stop), + step(1) + { } + + Range(T start, T stop) : + start(start), + stop(stop), + step(1) + { } + + Range(T start, T stop, T step) : + start(start), + stop(stop), + step(step) + { + this->step_check(); + } public: + Range() = delete; + Range(const Range &) = default; class Iterator { private: T value; @@ -78,27 +113,6 @@ namespace iter { } }; - Range() = delete; - Range(const Range &) = default; - Range(T stop) : - start(0), - stop(stop), - step(1) - { } - - Range(T start, T stop) : - start(start), - stop(stop), - step(1) - { } - - Range(T start, T stop, T step) : - start(start), - stop(stop), - step(step) - { - this->step_check(); - } Iterator begin() const { return Iterator(start, step); From eabedcac6f58314698a836ba2e87fcc73facd03f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 5 Oct 2013 02:08:17 -0700 Subject: [PATCH 0026/1866] Adds count --- count.hpp | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 count.hpp diff --git a/count.hpp b/count.hpp new file mode 100644 index 00000000..15119e8b --- /dev/null +++ b/count.hpp @@ -0,0 +1,35 @@ +#ifndef COUNT__H__ +#define COUNT__H__ + +#include "range.hpp" + +#include + +namespace iter { + + namespace { + typedef long DefaultRangeType; + } + + Range count() { + return range(DefaultRangeType(0), + std::numeric_limits::max()); + } + + template + Range 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(); + return range(start, stop, step); + } + + template + Range count(T start) { + return range(start, T(1)); + } +} + + +#endif //define COUNT__H__ + From 70b84291b98cc6c32963c18444e5f92965cc2d58 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 5 Oct 2013 02:08:33 -0700 Subject: [PATCH 0027/1866] Adds testcount --- tests/testcount.cpp | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 tests/testcount.cpp diff --git a/tests/testcount.cpp b/tests/testcount.cpp new file mode 100644 index 00000000..946d6841 --- /dev/null +++ b/tests/testcount.cpp @@ -0,0 +1,38 @@ +#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; +} From c160d7d27f1c6c61e49e9d02d6f651c796489948 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 5 Oct 2013 02:09:27 -0700 Subject: [PATCH 0028/1866] Adds testcount to SConstruct --- tests/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/SConstruct b/tests/SConstruct index 06332784..e8fbd4e8 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -18,6 +18,7 @@ progs = Split( ''' powerset moving_section imap + count ''') cxx_flags = '-Wall -Wextra -pedantic -std=c++11' From 41bb4685e315eb8dfac035a8f4e4b99fb6d847ec Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 5 Oct 2013 02:10:14 -0700 Subject: [PATCH 0029/1866] Adds testimap to Makefile --- tests/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index 7fadaf98..c3d0d83f 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -31,7 +31,8 @@ TESTS = \ testcombinations_with_replacement \ testcombinations \ testpowerset \ - testmoving_section + testmoving_section \ + testimap all: $(TESTS) From f95bb71812cd2a3e66bda2869f6e3c956b3db107 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 5 Oct 2013 02:10:37 -0700 Subject: [PATCH 0030/1866] Adds testcount to Makefile --- tests/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index c3d0d83f..209a3d2b 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -32,7 +32,8 @@ TESTS = \ testcombinations \ testpowerset \ testmoving_section \ - testimap + testimap \ + testcount all: $(TESTS) From 094aff499a1998206edf2d30baf3518170fccf96 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 5 Oct 2013 02:26:26 -0700 Subject: [PATCH 0031/1866] adds the rest of the tests to testimap --- tests/testimap.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/testimap.cpp b/tests/testimap.cpp index a2b74f5b..6f4e6f1f 100644 --- a/tests/testimap.cpp +++ b/tests/testimap.cpp @@ -11,5 +11,16 @@ int main() { 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'; + } + return 0; } From 58b47b9216542276aa5837b15a3585c8bbe7fb1d Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Sat, 5 Oct 2013 11:28:14 -0400 Subject: [PATCH 0032/1866] Got rid of two range specialization for zip iter --- tests/.gitignore | 1 + zip.hpp | 31 ++++++++++++++++++++++++------- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/tests/.gitignore b/tests/.gitignore index 5db5fc20..8bc90b6e 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -18,3 +18,4 @@ testtakewhile testcombinations testpowerset testmoving_section +testimap diff --git a/zip.hpp b/zip.hpp index a9286e97..927f480d 100644 --- a/zip.hpp +++ b/zip.hpp @@ -14,13 +14,30 @@ namespace iter { auto begin = zip_iter(containers.begin()...); auto end = zip_iter(containers.end()...); return iterator_range(begin,end); - } - /*template - auto zip_get(Tuple & t) ->decltype(*std::get(t))& - { - return *std::get(t); } - */ + template + struct zip_iter { + + private: + Iterator iter; + + public: + using Elem_t = decltype(*iter); + zip_iter(const Iterator & i) : + iter(i){ } + + auto operator*() -> decltype(std::tie(*iter)) + { + return std::tie(*iter); + } + zip_iter & operator++() { + ++iter; + return *this; + } + bool operator!=(const zip_iter & rhs) const { + return (this->iter != rhs.iter); + } + }; /* template struct zip_iter { @@ -46,7 +63,7 @@ namespace iter { bool operator!=(const zip_iter & rhs) const { return (this->iter1 != rhs.iter1) && (this->iter2 != rhs.iter2); } - }; + };*/ template struct zip_iter { From 97a3115930cba020b6c3d020b11b347073a876ad Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Sat, 5 Oct 2013 15:11:33 -0700 Subject: [PATCH 0033/1866] Adds filterfalse to TOC --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b4ba422e..f0d75640 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ library. ##### Table of Contents [range](#range)
[filter](#filter)
+[filterfalse](#filterfalse)
[takewhile](#takewhile)
[dropwhile](#dropwhile)
[enumerate](#enumerate)
From 8f775dfbb9405bd7734c1cd2fd55e4c758bac4f4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 5 Oct 2013 17:07:41 -0700 Subject: [PATCH 0034/1866] Adds testfilterfalse --- tests/testfilterfalse.cpp | 46 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tests/testfilterfalse.cpp diff --git a/tests/testfilterfalse.cpp b/tests/testfilterfalse.cpp new file mode 100644 index 00000000..2c1cd3f3 --- /dev/null +++ b/tests/testfilterfalse.cpp @@ -0,0 +1,46 @@ +#include + +#include +#include + +using iter::filterfalse; + +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 : 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'; + } + + return 0; +} From 961c4aead96fc89c181f95a13880719a5d5ce804 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 5 Oct 2013 17:08:19 -0700 Subject: [PATCH 0035/1866] Adds testfilterfalse to SConstruct and Makefile --- tests/Makefile | 3 ++- tests/SConstruct | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index 209a3d2b..fb57ac31 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -33,7 +33,8 @@ TESTS = \ testpowerset \ testmoving_section \ testimap \ - testcount + testcount \ + testfilterfalse all: $(TESTS) diff --git a/tests/SConstruct b/tests/SConstruct index e8fbd4e8..61ac24f4 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -19,6 +19,7 @@ progs = Split( ''' moving_section imap count + filterfalse ''') cxx_flags = '-Wall -Wextra -pedantic -std=c++11' From 40604998861ff8d64a2dcece3cbff6c2c657932e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 5 Oct 2013 17:08:51 -0700 Subject: [PATCH 0036/1866] Adds testfilterfalse to .gitignore --- tests/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/.gitignore b/tests/.gitignore index 8bc90b6e..ab2fff9a 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -19,3 +19,4 @@ testcombinations testpowerset testmoving_section testimap +testfilterfalse From 266acb4d2c00ca01f38af161617c6fbab2f1ed9a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 5 Oct 2013 17:09:07 -0700 Subject: [PATCH 0037/1866] Adds filterfalse.hpp --- filterfalse.hpp | 91 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 filterfalse.hpp diff --git a/filterfalse.hpp b/filterfalse.hpp new file mode 100644 index 00000000..578b57c2 --- /dev/null +++ b/filterfalse.hpp @@ -0,0 +1,91 @@ +#ifndef FILTERFALSE__H__ +#define FILTERFALSE__H__ + +#include "filter.hpp" + +namespace iter { + + //Forward declarations of FilterFalse and filterfalse + template + class FilterFalse; + + template + FilterFalse filterfalse(FilterFunc, Container &); + + template + class FilterFalse : public Filter { + // The filterfalse function is the only thing allowed to + // create a FilterFalse + friend FilterFalse filterfalse( + FilterFunc, Container &); + using Base = Filter; + + public: + using Filter::Filter; + + class Iterator { + protected: + typename Base::contained_iter_type sub_iter; + const typename Base::contained_iter_type sub_end; + FilterFunc filter_func; + + // skip every element that is true ender the predicate + void skip_passes() { + while (this->sub_iter != this->sub_end + && this->filter_func(*this->sub_iter)) { + ++this->sub_iter; + } + } + + public: + Iterator (typename Base::contained_iter_type iter, + typename Base::contained_iter_type end, + FilterFunc filter_func) : + sub_iter(iter), + sub_end(end), + filter_func(filter_func) + { + this->skip_passes(); + } + + typename Base::contained_iter_ret operator*() const { + return *this->sub_iter; + } + + Iterator & operator++() { + ++this->sub_iter; + this->skip_passes(); + return *this; + } + + bool operator!=(const Iterator & other) const { + return this->sub_iter != other.sub_iter; + } + }; + + Iterator begin() const { + return Iterator( + this->container.begin(), + this->container.end(), + this->filter_func); + } + + Iterator end() const { + return Iterator( + this->container.end(), + this->container.end(), + this->filter_func); + } + }; + + + template + FilterFalse filterfalse(FilterFunc filter_func, + Container & container) { + return FilterFalse(filter_func, container); + } +} + + + +#endif //ifndef FILTERFALSE__H__ From 5f0c29272faa6906b96a665bcf878bae3401a346 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 5 Oct 2013 17:18:42 -0700 Subject: [PATCH 0038/1866] Adds filterfalse to README --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ca6752c2..b4ba422e 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,20 @@ Called as `filter(predicate, iterable)`. The predicate can be any callable. Prints values greater than 4: 5 6 7 8 ```c++ -vector vec{1, 5, 6, 7, 3, 2, 8, 3, 2, 1}; +vector vec{1, 5, 4, 6, 7, 3, 2, 8, 3, 2, 1}; +for (auto i : filter([] (int i) { return i > 4; }, vec)) { + cout << i <<'\n'; +} + +``` + +filterfalse +----------- +Similar to filter, but only prints values that are false under the predicate. + +Prints values not greater than 4: 1 4 3 2 3 2 1 +```c++ +vector vec{1, 5, 4, 6, 7, 3, 2, 8, 3, 2, 1}; for (auto i : filter([] (int i) { return i > 4; }, vec)) { cout << i <<'\n'; } From 7df0dfcb03149dce493ebefbb9aecc09fee1787d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 5 Oct 2013 17:19:15 -0700 Subject: [PATCH 0039/1866] Changes filter.hpp to be subclassed --- filter.hpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/filter.hpp b/filter.hpp index 8671a73a..8e442e2b 100644 --- a/filter.hpp +++ b/filter.hpp @@ -18,16 +18,16 @@ namespace iter { friend Filter filter(FilterFunc, Container &); - // Type of the Container::Iterator, but since the name of that - // iterator can be anything, we have to grab it with this - using contained_iter_type = - decltype(std::declval().begin()); + protected: + // Type of the Container::Iterator, but since the name of that + // iterator can be anything, we have to grab it with this + using contained_iter_type = + decltype(std::declval().begin()); - // The type returned when dereferencing the Container::Iterator - using contained_iter_ret = - decltype(std::declval().operator*()); + // The type returned when dereferencing the Container::Iterator + using contained_iter_ret = + decltype(std::declval().operator*()); - private: Container & container; FilterFunc filter_func; @@ -42,7 +42,7 @@ namespace iter { public: class Iterator { - private: + protected: contained_iter_type sub_iter; const contained_iter_type sub_end; FilterFunc filter_func; From ac6e4ea445fa91c582cd4c7d4db6400a55c2b97b Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Sat, 5 Oct 2013 23:46:47 -0400 Subject: [PATCH 0040/1866] Did grouper from python recipes --- grouper.hpp | 69 +++++++++++++++++++++++++++++++++++++++++++ tests/.gitignore | 2 ++ tests/Makefile | 3 +- tests/testgrouper.cpp | 15 ++++++++++ 4 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 grouper.hpp create mode 100644 tests/testgrouper.cpp diff --git a/grouper.hpp b/grouper.hpp new file mode 100644 index 00000000..879a419d --- /dev/null +++ b/grouper.hpp @@ -0,0 +1,69 @@ +#ifndef GROUPER_HPP +#define GROUPER_HPP + +#include "iterator_range.hpp" +#include +#include +#include +#include + +namespace iter { + template + struct grouper_iter; + template + iterator_range> + grouper(Container & container, size_t s) { + auto begin = grouper_iter(container,s); + auto end = grouper_iter(container); + return iterator_range>(begin,end); + } + + template + struct grouper_iter { + Container & container; + using Iterator = decltype(container.begin()); + std::vector group; + size_t group_size = 0; + bool not_done = true; + grouper_iter(Container & c, size_t s) : + container(c),group_size(s) + { + for (size_t i = 0; i < group_size; ++i) + group.push_back(container.begin()+i); + } + //seems like constructor is same as moving_section_iter + grouper_iter(Container & c) : container(c) + //creates the end iterator + { + group.push_back(container.end()); + } + + grouper_iter & operator++() { + for (auto & iter : group) { + iter += group_size; + } + return *this; + } + bool operator!=(const grouper_iter &) { + return not_done; + } + using Deref_type = std::vector())>::type>>; + Deref_type operator*() + { + Deref_type vec; + for (auto i : group) { + if(i == container.end()) { + not_done = false; + break; + } + //if the group is at the end the vector will be smaller + else { + vec.push_back(*i); + } + } + return vec; + } + }; +} + +#endif //MOVING_SECTION_HPP diff --git a/tests/.gitignore b/tests/.gitignore index ab2fff9a..38e72819 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -20,3 +20,5 @@ testpowerset testmoving_section testimap testfilterfalse +testcount +testgrouper diff --git a/tests/Makefile b/tests/Makefile index fb57ac31..58640431 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -34,7 +34,8 @@ TESTS = \ testmoving_section \ testimap \ testcount \ - testfilterfalse + testfilterfalse \ + testgrouper all: $(TESTS) diff --git a/tests/testgrouper.cpp b/tests/testgrouper.cpp new file mode 100644 index 00000000..b951b158 --- /dev/null +++ b/tests/testgrouper.cpp @@ -0,0 +1,15 @@ +#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() = 90; + } + std::cout << std::endl; + } + return 0; +} From 9e3b3a228d2d22b2b49d0980275ebad70b2e7bcf Mon Sep 17 00:00:00 2001 From: Eitan Adler Date: Sun, 6 Oct 2013 02:00:36 -0400 Subject: [PATCH 0041/1866] Fix sconstruct: 'c++' is the C++ compiler. There is no reason to assume either clang++ or g++. /usr/local/include must be included on modern unixes to use boost. --- tests/SConstruct | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/SConstruct b/tests/SConstruct index 4720ceae..5c2f74ba 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -24,9 +24,9 @@ progs = Split( ''' filterfalse ''') -cxx = 'clang++' -cxx_flags = ' -Wall -Wextra -pedantic -std=c++11 ' -ldflags = '' +cxx = 'c++' +cxx_flags = ' -Wall -Wextra -pedantic -std=c++11 -I/usr/local/include' +ldflags = ' -L/usr/local/lib' # if on MAC, needs the linker flag for -stdlib=libc++ if platform.system() == 'Darwin': From d630c1847958ba0704f97781572884eb8055d48a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Oct 2013 00:43:31 -0700 Subject: [PATCH 0042/1866] Adds check for mac to SConstruct --- tests/SConstruct | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/SConstruct b/tests/SConstruct index 61ac24f4..d6e2f747 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -1,3 +1,5 @@ +import platform + progs = Split( ''' cycle enumerate @@ -22,10 +24,11 @@ progs = Split( ''' filterfalse ''') -cxx_flags = '-Wall -Wextra -pedantic -std=c++11' +cxx_flags = ' -Wall -Wextra -pedantic -std=c++11 ' + +if platform.system() == 'Darwin': + cxx_flags += ' -stdlib=libc++ ' for p in progs: - Program(target='test{0}'.format(p), source='test{0}.cpp'.format(p), + Program(source='test{0}.cpp'.format(p), CXXFLAGS=cxx_flags, CPPPATH='..', CXX='clang++') - - From 03393170057da4dd97f3b3c11e949e08c75a5cbc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Oct 2013 00:44:16 -0700 Subject: [PATCH 0043/1866] Removes Makefile. All scons now --- tests/Makefile | 42 ------------------------------------------ 1 file changed, 42 deletions(-) delete mode 100644 tests/Makefile diff --git a/tests/Makefile b/tests/Makefile deleted file mode 100644 index fb57ac31..00000000 --- a/tests/Makefile +++ /dev/null @@ -1,42 +0,0 @@ -CXX := clang++ -CXXFLAGS := -Wall -Wextra -pedantic -std=c++11 - -KERNEL := $(shell uname -s) -ifeq ($(KERNEL),Darwin) -ifeq ($(CXX),clang++) - CXXFLAGS += -stdlib=libc++ -endif -endif - -LINK.o = $(LINK.cc) - -CPPFLAGS := -I".." - -TESTS = \ - testchain \ - testcycle \ - testenumerate \ - testrange \ - testzip \ - testslice \ - testreverse \ - testfilter \ - testrepeat \ - testtakewhile \ - testdropwhile \ - testzip_longest \ - testproduct \ - testpermutations \ - testcompress \ - testcombinations_with_replacement \ - testcombinations \ - testpowerset \ - testmoving_section \ - testimap \ - testcount \ - testfilterfalse - -all: $(TESTS) - -clean: - rm -f *.o $(TESTS) From 2385f8baf734c65b4a1bd0e6b5e507a1378a748b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Oct 2013 01:05:13 -0700 Subject: [PATCH 0044/1866] Fixes mac check to use the linker flags I'm still fairly new to scons though so I'm sure this can be improved. --- tests/SConstruct | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/SConstruct b/tests/SConstruct index d6e2f747..197e4a97 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -24,11 +24,13 @@ progs = Split( ''' filterfalse ''') +cxx = 'clang++' cxx_flags = ' -Wall -Wextra -pedantic -std=c++11 ' -if platform.system() == 'Darwin': - cxx_flags += ' -stdlib=libc++ ' +# if on MAC, needs the linker flag for -stdlib=libc++ +ldflags = '-stdlib=libc++' if platform.system() == 'Darwin' else '' for p in progs: Program(source='test{0}.cpp'.format(p), - CXXFLAGS=cxx_flags, CPPPATH='..', CXX='clang++') + CXXFLAGS=cxx_flags, CPPPATH='..', CXX=cxx, + LINKFLAGS=ldflags) From 28d3f1d190daaecb80306dc5438c6d72e93bbf8e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Oct 2013 01:33:27 -0700 Subject: [PATCH 0045/1866] Fixes SConstruct mac check (again) CXXFLAGS needs -stdlib=libc++ too. --- tests/SConstruct | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/SConstruct b/tests/SConstruct index 197e4a97..4720ceae 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -26,9 +26,12 @@ progs = Split( ''' cxx = 'clang++' cxx_flags = ' -Wall -Wextra -pedantic -std=c++11 ' +ldflags = '' # if on MAC, needs the linker flag for -stdlib=libc++ -ldflags = '-stdlib=libc++' if platform.system() == 'Darwin' else '' +if platform.system() == 'Darwin': + ldflags += ' -stdlib=libc++ ' + cxx_flags += ' -stdlib=libc++ ' for p in progs: Program(source='test{0}.cpp'.format(p), From 4ac571d1ba24514a6af7ba092a6d6c05c2e90011 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Sun, 6 Oct 2013 09:57:13 -0700 Subject: [PATCH 0046/1866] Adds imap to README --- README.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/README.md b/README.md index f0d75640..21d3cbc1 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ library. [cycle](#cycle)
[compress](#compress)
[zip](#zip)
+[imap](#imap)
[chain](#chain)
[reverse](#reverse)
[slice](#slice)
@@ -178,6 +179,37 @@ range instead of the shortest. because of that you have to return a to (`std::optional` when it is released, if ever) +imap +---- + +Takes a function and one or more iterables. The number of iterables must +match the number of arguments to the function. Applies the function to +each element (or elements) in the iterable(s). Terminates on the shortest +sequence. + +Prints the squares of the numbers in vec: `1 4 9 16 25` +```c++ +vector vec{1, 2, 3, 4, 5}; +for (auto i : imap([] (int x) {return x * x;}, vec)) { + cout << i << '\n'; +} +``` + +With more than one sequence, the below adds corresponding elements from +each vector together, printing `11 23 35 47 59 71` +```c++ +vector vec1{1, 3, 5, 7, 9, 11}; +vector vec2{10, 20, 30, 40, 50, 60}; +for (auto i : imap([] (int x, int y) { return x + y; }, vec1, vec2)) { + cout << i << '\n'; +} +``` + +*Note*: The name `imap` is chosen to prevent confusion/collision with +`std::map`, and because it is more related to `itertools.imap` than +the python builtin `map`. + + compress -------- From ef0bcf2ad302de7881c68d715b0df23d2f7e480c Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Sun, 6 Oct 2013 10:08:33 -0700 Subject: [PATCH 0047/1866] Adds double range use case to README --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 21d3cbc1..d9d9ecdf 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,16 @@ for (auto i : range(2, -3, -1)) { } ``` +In addition to normal integer range operations, doubles and +other numeric types are supported through the template + +Prints: `5.0 5.5 6.0` ... `9.5` +```c++ +for(auto i : range(5.0, 10.0, 0.5)) { + cout << i << '\n'; +} +``` + enumerate --------- From 9bd047b0591bc47c36c29c7913f66e8740204c45 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Oct 2013 13:11:27 -0700 Subject: [PATCH 0048/1866] Adds `` tags around output in examples --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index d9d9ecdf..176d87db 100644 --- a/README.md +++ b/README.md @@ -32,28 +32,28 @@ range Uses an underlying iterator to acheive the same effect of the python range function. `range` can be used in three different ways: -Only the stopping point is provided. Prints 0 1 2 3 4 5 6 7 8 9 +Only the stopping point is provided. Prints `0 1 2 3 4 5 6 7 8 9` ```c++ for (auto i : range(10)) { cout << i << '\n'; } ``` -The start and stop are both provided. Prints 10 11 12 13 14 +The start and stop are both provided. Prints `10 11 12 13 14` ```c++ for (auto i : range(10, 15)) { cout << i << '\n'; } ``` -The start, stop, and step are all provided. Prints 20 22 24 26 28 +The start, stop, and step are all provided. Prints `20 22 24 26 28` ```c++ for (auto i : range(20, 30, 2)) { cout << i << '\n'; } ``` -Negative values are allowed as well. Prints 2 1 0 -1 -2 +Negative values are allowed as well. Prints `2 1 0 -1 -2` ```c++ for (auto i : range(2, -3, -1)) { cout << i << '\n'; @@ -92,7 +92,7 @@ filter Called as `filter(predicate, iterable)`. The predicate can be any callable. `filter` will only yield values that are true under the predicate. -Prints values greater than 4: 5 6 7 8 +Prints values greater than 4: `5 6 7 8` ```c++ vector vec{1, 5, 4, 6, 7, 3, 2, 8, 3, 2, 1}; for (auto i : filter([] (int i) { return i > 4; }, vec)) { @@ -105,7 +105,7 @@ filterfalse ----------- Similar to filter, but only prints values that are false under the predicate. -Prints values not greater than 4: 1 4 3 2 3 2 1 +Prints values not greater than 4: `1 4 3 2 3 2 1 ` ```c++ vector vec{1, 5, 4, 6, 7, 3, 2, 8, 3, 2, 1}; for (auto i : filter([] (int i) { return i > 4; }, vec)) { @@ -119,7 +119,7 @@ takewhile Yields elements from an iterable until the first element that is false under the predicate is encountered. -Prints 1 2 3 4. (5 is false under the predicate) +Prints `1 2 3 4`. (5 is false under the predicate) ```c++ vector ivec{1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1}; for (auto i : takewhile([] (int i) {return i < 5;}, ivec)) { @@ -132,7 +132,7 @@ dropwhile Yields all elements after and including the first element that is false under the predicate. -Prints 5 6 7 1 2 +Prints `5 6 7 1 2` ```c++ vector ivec{1, 2, 3, 4, 5, 6, 7, 1, 2}; for (auto i : dropwhile([] (int i) {return i < 5;}, ivec)) { @@ -146,7 +146,7 @@ cycle Repeatedly produce all values of an iterable. The loop will be infinite, so a `break` is necessary to exit. -Prints 1 2 3 repeatedly until `some_condition` is true +Prints `1 2 3` repeatedly until `some_condition` is true ```c++ vector vec{1, 2, 3}; for (auto i : cycle(vec)) { From d604931a045b5e75588584388c0ad9f0ab5461d7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Oct 2013 13:12:31 -0700 Subject: [PATCH 0049/1866] Modifiies tests --- tests/testimap.cpp | 5 +++++ tests/testrange.cpp | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/testimap.cpp b/tests/testimap.cpp index 6f4e6f1f..32ded424 100644 --- a/tests/testimap.cpp +++ b/tests/testimap.cpp @@ -22,5 +22,10 @@ int main() { 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'; + } + return 0; } diff --git a/tests/testrange.cpp b/tests/testrange.cpp index 5fa2a75e..fd7a294f 100644 --- a/tests/testrange.cpp +++ b/tests/testrange.cpp @@ -35,7 +35,7 @@ int main() } std::cout << "Tests with different types" << std::endl; - for(auto i : range(0.0, 10.0, 0.5)) { + for(auto i : range(5.0, 10.0, 0.5)) { std::cout << i << std::endl; } From 79205fad405d1bad1858b2c73808db018cd580b1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Oct 2013 13:13:31 -0700 Subject: [PATCH 0050/1866] Puts `` around compress output in REAME --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 176d87db..1ae99384 100644 --- a/README.md +++ b/README.md @@ -226,7 +226,7 @@ compress Yields only the values corresponding to true in the selectors iterable. Terminates on the shortest sequence. -Prints 2 6 +Prints `2 6` ```c++ vector ivec{1, 2, 3, 4, 5, 6}; vector bvec{false, true, false, false, false, true}; From e9b6a707761e3803993d57e79aa045384df41fcf Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Sun, 6 Oct 2013 22:38:43 -0400 Subject: [PATCH 0051/1866] fixed slight error in grouper if given an empty range --- grouper.hpp | 5 +++++ tests/.gitignore | 1 + tests/SConstruct | 1 + tests/testgrouper.cpp | 16 +++++++++++++++- 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/grouper.hpp b/grouper.hpp index 879a419d..562d7b31 100644 --- a/grouper.hpp +++ b/grouper.hpp @@ -28,6 +28,11 @@ namespace iter { grouper_iter(Container & c, size_t s) : container(c),group_size(s) { + //if the group size is 0 or the container is empty produce nothing + if (group_size == 0 || !(container.begin() != container.end())) { + not_done = false; + return; + } for (size_t i = 0; i < group_size; ++i) group.push_back(container.begin()+i); } diff --git a/tests/.gitignore b/tests/.gitignore index 38e72819..450ff7b2 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -22,3 +22,4 @@ testimap testfilterfalse testcount testgrouper +.sconsign.dblite diff --git a/tests/SConstruct b/tests/SConstruct index 5c2f74ba..08eb17de 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -22,6 +22,7 @@ progs = Split( ''' imap count filterfalse + grouper ''') cxx = 'c++' diff --git a/tests/testgrouper.cpp b/tests/testgrouper.cpp index b951b158..b98a1af5 100644 --- a/tests/testgrouper.cpp +++ b/tests/testgrouper.cpp @@ -3,13 +3,27 @@ #include using iter::grouper; int main() { - std::vector v = {1,2,3,4,5,6,7,8,9}; + 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 << std::endl; + } + for (auto sec : grouper(v,3)) { for (auto i : sec) { std::cout << i << " "; //i.get() = 90; } std::cout << std::endl; } + 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"; + } + } return 0; } From 462ca9505e2fb29eada1cefc378ba513f7e51532 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 7 Oct 2013 01:57:53 -0700 Subject: [PATCH 0052/1866] Adds default case to filter filter(iterable) filters out the items in iterable that themselves are false --- filter.hpp | 93 +++++++++++++++++++++++++++++++++++++++++++- tests/testfilter.cpp | 7 ++++ 2 files changed, 99 insertions(+), 1 deletion(-) diff --git a/filter.hpp b/filter.hpp index 8e442e2b..1a611bce 100644 --- a/filter.hpp +++ b/filter.hpp @@ -98,13 +98,104 @@ namespace iter { }; - // Helper function to instantiate a Filter + // Helper function to instantiate a FilterDefault template Filter filter( FilterFunc filter_func, Container & container) { return Filter(filter_func, container); } + //Forward declarations of FilterDefault and filter + template + class FilterDefault; + + template + FilterDefault filter(Container &); + + template + class FilterDefault { + // The filter function is the only thing allowed to create a FilterDefault + friend FilterDefault filter(Container &); + + + protected: + // Type of the Container::Iterator, but since the name of that + // iterator can be anything, we have to grab it with this + using contained_iter_type = + decltype(std::declval().begin()); + + // The type returned when dereferencing the Container::Iterator + using contained_iter_ret = + decltype(std::declval().operator*()); + + Container & container; + + // Value constructor for use only in the filter function + FilterDefault(Container & container) : + container(container) + { } + FilterDefault () = delete; + FilterDefault & operator=(const FilterDefault &) = delete; + // Default copy constructor used + + public: + class Iterator { + protected: + contained_iter_type sub_iter; + const contained_iter_type sub_end; + + // increment until the iterator points to is true on the + // predicate. Called by constructor and operator++ + void skip_failures() { + while (this->sub_iter != this->sub_end + && !(*this->sub_iter)) { + ++this->sub_iter; + } + } + + public: + Iterator (contained_iter_type iter, + contained_iter_type end) : + sub_iter(iter), + sub_end(end) + { + this->skip_failures(); + } + + contained_iter_ret operator*() const { + return *this->sub_iter; + } + + Iterator & operator++() { + ++this->sub_iter; + this->skip_failures(); + return *this; + } + + bool operator!=(const Iterator & other) const { + return this->sub_iter != other.sub_iter; + } + }; + + Iterator begin() const { + return Iterator( + this->container.begin(), + this->container.end()); + } + + Iterator end() const { + return Iterator( + this->container.end(), + this->container.end()); + } + + }; + + // Helper function to instantiate a FilterDefault + template + FilterDefault filter(Container & container) { + return FilterDefault(container); + } } #endif //ifndef FILTER__H__ diff --git a/tests/testfilter.cpp b/tests/testfilter.cpp index 05ce83f3..63718646 100644 --- a/tests/testfilter.cpp +++ b/tests/testfilter.cpp @@ -42,5 +42,12 @@ int main() { 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'; + } + + return 0; } From b537ab010e04b2279d21609297769c8aff600578 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 7 Oct 2013 02:12:55 -0700 Subject: [PATCH 0053/1866] Formatting on grouper --- grouper.hpp | 72 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/grouper.hpp b/grouper.hpp index 562d7b31..94273260 100644 --- a/grouper.hpp +++ b/grouper.hpp @@ -9,56 +9,72 @@ namespace iter { template - struct grouper_iter; + class grouper_iter; + template - iterator_range> - grouper(Container & container, size_t s) { - auto begin = grouper_iter(container,s); - auto end = grouper_iter(container); - return iterator_range>(begin,end); - } + iterator_range> grouper( + Container & container, size_t s) { + auto begin = grouper_iter(container, s); + auto end = grouper_iter(container); + return iterator_range>(begin, end); + } template - struct grouper_iter { + class grouper_iter { + private: Container & container; using Iterator = decltype(container.begin()); + using Deref_type = + std::vector< + std::reference_wrapper< + typename std::remove_reference< + decltype(*std::declval())>::type>>; + + std::vector group; + size_t group_size = 0; bool not_done = true; + + public: grouper_iter(Container & c, size_t s) : container(c),group_size(s) { - //if the group size is 0 or the container is empty produce nothing - if (group_size == 0 || !(container.begin() != container.end())) { - not_done = false; + // if the group size is 0 or the container is empty produce + // nothing + if (this->group_size == 0 || + !(this->container.begin() != this->container.end())) { + this->not_done = false; return; } - for (size_t i = 0; i < group_size; ++i) - group.push_back(container.begin()+i); + for (size_t i = 0; i < this->group_size; ++i) + this->group.push_back(this->container.begin() + i); } - //seems like constructor is same as moving_section_iter - grouper_iter(Container & c) : container(c) - //creates the end iterator + + //seems like conclassor is same as moving_section_iter + grouper_iter(Container & c) : + container(c) { + //creates the end iterator group.push_back(container.end()); } grouper_iter & operator++() { - for (auto & iter : group) { - iter += group_size; + for (auto & iter : this->group) { + iter += this->group_size; } return *this; } - bool operator!=(const grouper_iter &) { - return not_done; + + bool operator!=(const grouper_iter &) const { + return this->not_done; } - using Deref_type = std::vector())>::type>>; - Deref_type operator*() - { + + Deref_type operator*() { Deref_type vec; - for (auto i : group) { - if(i == container.end()) { - not_done = false; + for (auto i : this->group) { + if(i == this->container.end()) { + this->not_done = false; break; } //if the group is at the end the vector will be smaller @@ -68,7 +84,7 @@ namespace iter { } return vec; } - }; + }; } -#endif //MOVING_SECTION_HPP +#endif // ifndef GROUPER_HPP From 1084c753c761c0e17a98100a10788a5c996a9bc6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 7 Oct 2013 02:21:42 -0700 Subject: [PATCH 0054/1866] Shortens using in enumerate --- enumerate.hpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 30db629c..2c3dad18 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -25,21 +25,21 @@ namespace iter { template class Enumerable { - // The only thing allowed to directly instantiate an Enumerable is - // the enumerate function - friend Enumerable enumerate(Container &); + private: + Container & container; + // The only thing allowed to directly instantiate an Enumerable is + // the enumerate function + friend Enumerable enumerate(Container &); - // Type of the Container::Iterator, but since the name of that - // iterator can be anything, we have to grab it with this - using contained_iter_type = - decltype(std::declval().begin()); + // Type of the Container::Iterator, but since the name of that + // iterator can be anything, we have to grab it with this + using contained_iter_type = + decltype(container.begin()); - // The type returned when dereferencing the Container::Iterator - using contained_iter_ret = - decltype(std::declval().operator*()); + // The type returned when dereferencing the Container::Iterator + using contained_iter_ret = + decltype(container.begin().operator*()); - private: - Container & container; // Value constructor for use only in the enumerate function Enumerable(Container & container) : container(container) { } From 440d8d0ad79bf9c978d3c268475bae31868bf668 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 7 Oct 2013 02:23:48 -0700 Subject: [PATCH 0055/1866] Shortens using in compress --- compress.hpp | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/compress.hpp b/compress.hpp index 92761729..989c5983 100644 --- a/compress.hpp +++ b/compress.hpp @@ -17,27 +17,24 @@ namespace iter { template class Compressed { - // The only thing allowed to directly instantiate an Compressed is - // the compress function - friend Compressed compress( - Container &, Selector &); + private: + Container & container; + Selector & selectors; - // Type of the Container::Iterator, but since the name of that - // iterator can be anything, we have to grab it with this - using contained_iter_type = - decltype(std::declval().begin()); + // The only thing allowed to directly instantiate an Compressed is + // the compress function + friend Compressed compress( + Container &, Selector &); - // The type returned when dereferencing the Container::Iterator - using contained_iter_ret = - decltype(std::declval().operator*()); + // Type of the Container::Iterator, but since the name of that + // iterator can be anything, we have to grab it with this + using contained_iter_type = decltype(container.begin()); - // Selector::Iterator type - using selector_iter_type = - decltype(std::declval().begin()); + // The type returned when dereferencing the Container::Iterator + using contained_iter_ret = decltype(container.begin().operator*()); - private: - Container & container; - Selector & selectors; + // Selector::Iterator type + using selector_iter_type = decltype(selectors.begin()); // Value constructor for use only in the compress function Compressed(Container & container, Selector & selectors) : From 7e0621d366935cec7684325b3f038c17d8743a41 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 7 Oct 2013 02:25:14 -0700 Subject: [PATCH 0056/1866] Removes a comment from filter --- filter.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/filter.hpp b/filter.hpp index 1a611bce..d0cb6246 100644 --- a/filter.hpp +++ b/filter.hpp @@ -144,8 +144,6 @@ namespace iter { contained_iter_type sub_iter; const contained_iter_type sub_end; - // increment until the iterator points to is true on the - // predicate. Called by constructor and operator++ void skip_failures() { while (this->sub_iter != this->sub_end && !(*this->sub_iter)) { From 7d06b1eed2f42c0f9a2ff59c5a762a93041f4ca6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 7 Oct 2013 02:27:58 -0700 Subject: [PATCH 0057/1866] Shortens usings in dropwhile --- dropwhile.hpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index 8b60da37..ffba1d16 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -14,21 +14,20 @@ namespace iter { template class DropWhile { - friend DropWhile dropwhile( - FilterFunc, Container &); - - // Type of the Container::Iterator, but since the name of that - // iterator can be anything, we have to grab it with this - using contained_iter_type = - decltype(std::declval().begin()); - - // The type returned when dereferencing the Container::Iterator - using contained_iter_ret = - decltype(std::declval().operator*()); - private: Container & container; FilterFunc filter_func; + + friend DropWhile dropwhile( + FilterFunc, Container &); + + // Type of the Container::Iterator, but since the name of that + // iterator can be anything, we have to grab it with this + using contained_iter_type = decltype(container.begin()); + + // The type returned when dereferencing the Container::Iterator + using contained_iter_ret = decltype(container.begin().operator*()); + // Value constructor for use only in the dropwhile function DropWhile(FilterFunc filter_func, Container & container) : From 8645fc9cb8e08e3866c47abd9313fb9ec33b438e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 7 Oct 2013 02:31:59 -0700 Subject: [PATCH 0058/1866] Shortens using in filter --- filter.hpp | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/filter.hpp b/filter.hpp index 1a611bce..eca5e29e 100644 --- a/filter.hpp +++ b/filter.hpp @@ -14,22 +14,19 @@ namespace iter { template class Filter { - // The filter function is the only thing allowed to create a Filter - friend Filter filter(FilterFunc, Container &); - - protected: + Container & container; + FilterFunc filter_func; + + // The filter function is the only thing allowed to create a Filter + friend Filter filter(FilterFunc, + Container &); // Type of the Container::Iterator, but since the name of that // iterator can be anything, we have to grab it with this - using contained_iter_type = - decltype(std::declval().begin()); + using contained_iter_type = decltype(container.begin()); // The type returned when dereferencing the Container::Iterator - using contained_iter_ret = - decltype(std::declval().operator*()); - - Container & container; - FilterFunc filter_func; + using contained_iter_ret = decltype(container.begin().operator*()); // Value constructor for use only in the filter function Filter(FilterFunc filter_func, Container & container) : @@ -114,22 +111,19 @@ namespace iter { template class FilterDefault { - // The filter function is the only thing allowed to create a FilterDefault - friend FilterDefault filter(Container &); - - protected: + Container & container; + + // The filter function is the only thing allowed to create a + // FilterDefault + friend FilterDefault filter(Container &); // Type of the Container::Iterator, but since the name of that // iterator can be anything, we have to grab it with this - using contained_iter_type = - decltype(std::declval().begin()); + using contained_iter_type = decltype(container.begin()); // The type returned when dereferencing the Container::Iterator - using contained_iter_ret = - decltype(std::declval().operator*()); + using contained_iter_ret = decltype(container.begin().operator*()); - Container & container; - // Value constructor for use only in the filter function FilterDefault(Container & container) : container(container) From 3ff96a41beba5cb77cabe32566ae27d92287d76c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 7 Oct 2013 02:37:55 -0700 Subject: [PATCH 0059/1866] Shortens usings in takewhile --- takewhile.hpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/takewhile.hpp b/takewhile.hpp index bbb70d49..0a1e033d 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -14,27 +14,26 @@ namespace iter { template class TakeWhile { - friend TakeWhile takewhile( - FilterFunc, Container &); - - // Type of the Container::Iterator, but since the name of that - // iterator can be anything, we have to grab it with this - using contained_iter_type = - decltype(std::declval().begin()); - - // The type returned when dereferencing the Container::Iterator - using contained_iter_ret = - decltype(std::declval().operator*()); - private: Container & container; FilterFunc filter_func; - + + friend TakeWhile takewhile( + FilterFunc, Container &); + + // Type of the Container::Iterator, but since the name of that + // iterator can be anything, we have to grab it with this + using contained_iter_type = decltype(container.begin()); + + // The type returned when dereferencing the Container::Iterator + using contained_iter_ret = decltype(container.begin().operator*()); + // Value constructor for use only in the takewhile function TakeWhile(FilterFunc filter_func, Container & container) : container(container), filter_func(filter_func) { } + TakeWhile () = delete; TakeWhile & operator=(const TakeWhile &) = delete; // Default copy constructor used From 3f07249d11c956e9f9a146c959a2fee02dc0696a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 7 Oct 2013 02:39:15 -0700 Subject: [PATCH 0060/1866] Adds imap test with different size vectors --- tests/testimap.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/testimap.cpp b/tests/testimap.cpp index 32ded424..60f8ede0 100644 --- a/tests/testimap.cpp +++ b/tests/testimap.cpp @@ -27,5 +27,10 @@ int main() { 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'; + } + return 0; } From e7d959c6d5cf3495caca500866b062c0c2ebe977 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Mon, 7 Oct 2013 23:55:26 -0400 Subject: [PATCH 0061/1866] added temp test to combinations --- tests/testcombinations.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/testcombinations.cpp b/tests/testcombinations.cpp index 194f77c0..422c088e 100644 --- a/tests/testcombinations.cpp +++ b/tests/testcombinations.cpp @@ -17,6 +17,13 @@ int main() { for (auto j : i ) std::cout << j << " "; std::cout<{1,2,3,4},3)) { + for (auto j : i ) std::cout << j << " "; + std::cout< Date: Tue, 8 Oct 2013 00:16:57 -0400 Subject: [PATCH 0062/1866] added perfect forwarding to chain, all previous tests work fine, but funky behavior with temp vector --- chain.hpp | 12 ++++++------ tests/SConstruct | 1 + tests/testchain.cpp | 5 +++++ tests/testgrouper.cpp | 9 +++++++++ 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/chain.hpp b/chain.hpp index a825e1d5..ad8e3226 100644 --- a/chain.hpp +++ b/chain.hpp @@ -16,7 +16,7 @@ namespace iter { const Iterator end;//never really used but kept it for consistency public: - chain_iter(Container & container, bool is_end=false) : + chain_iter(Container && container, bool is_end=false) : begin(container.begin()),end(container.end()) { if(is_end) begin = container.end(); } @@ -44,10 +44,10 @@ namespace iter { chain_iter next_iter; public: - chain_iter(Container & container, Containers& ... rest, bool is_end=false) : + chain_iter(Container && container, Containers&& ... containers, bool is_end=false) : begin(container.begin()), end(container.end()), - next_iter(rest...,is_end) { + next_iter(std::forward(containers)...,is_end) { if(is_end) begin = container.end(); } @@ -79,12 +79,12 @@ namespace iter { } }; template - iterator_range> chain(Containers& ... containers) + iterator_range> chain(Containers&& ... containers) { auto begin = - chain_iter(containers...); + chain_iter(std::forward(containers)...); auto end = - chain_iter(containers...,true); + chain_iter(std::forward(containers)...,true); return iterator_range>(begin,end); } diff --git a/tests/SConstruct b/tests/SConstruct index 08eb17de..cd08614c 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -23,6 +23,7 @@ progs = Split( ''' count filterfalse grouper + chain ''') cxx = 'c++' diff --git a/tests/testchain.cpp b/tests/testchain.cpp index d0b88062..79015907 100644 --- a/tests/testchain.cpp +++ b/tests/testchain.cpp @@ -41,6 +41,11 @@ int main() { for (auto i : iter::chain(vec1,arr1,arr2)) { std::cout << i << std::endl; } + //test only works with perfect forwarding + std::cout<{1,2,3,4,5},std::array{{6,7,8,9}},std::vector(20))) { + std::cout << i << std::endl; + } } return 0; } diff --git a/tests/testgrouper.cpp b/tests/testgrouper.cpp index b98a1af5..50b18554 100644 --- a/tests/testgrouper.cpp +++ b/tests/testgrouper.cpp @@ -25,5 +25,14 @@ int main() { std::cout << i << " Shouldn't print\n"; } } + //works when perfect forwarding implemented + /* + for (auto sec : grouper({1,2,3,4,5,6,7,8},3)) { + for (auto i : sec) { + std::cout << i << " "; + } + std::cout << std::endl; + } + */ return 0; } From 8fbf1706ac3ef38fe213250fa29f7a47140fd4ba Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Tue, 8 Oct 2013 00:45:51 -0400 Subject: [PATCH 0063/1866] added perfect forwarding with zip, still getting strange temp vector behavior --- tests/testchain.cpp | 4 +++- tests/testzip.cpp | 8 ++++++++ zip.hpp | 3 ++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/tests/testchain.cpp b/tests/testchain.cpp index 79015907..46ac02a3 100644 --- a/tests/testchain.cpp +++ b/tests/testchain.cpp @@ -4,8 +4,10 @@ #include #include #include +#include using iter::chain; +using il = std::initializer_list; int main() { { @@ -43,7 +45,7 @@ int main() { } //test only works with perfect forwarding std::cout<{1,2,3,4,5},std::array{{6,7,8,9}},std::vector(20))) { + for (auto i : chain(il{1,2,3,4,5},il{6,7,8,9},il{10,11,12})) { std::cout << i << std::endl; } } diff --git a/tests/testzip.cpp b/tests/testzip.cpp index 6f635a97..32483d83 100644 --- a/tests/testzip.cpp +++ b/tests/testzip.cpp @@ -69,6 +69,14 @@ int main() { << std::get<3>(e) << std::endl; } std::cout<{1,2,3,4,5}, + std::initializer_list{"asdfas","aaron","ryan"}, + std::initializer_list{1.1,2.2,3.3,4.4})) { + + std::cout << std::get<0>(e) << " " + << std::get<1>(e) << " " + << std::get<2>(e) << std::endl; + } } return 0; } diff --git a/zip.hpp b/zip.hpp index 927f480d..1542f92b 100644 --- a/zip.hpp +++ b/zip.hpp @@ -8,7 +8,7 @@ namespace iter { template struct zip_iter; template - auto zip(Containers & ... containers) -> + auto zip(Containers && ... containers) -> iterator_range> { auto begin = zip_iter(containers.begin()...); @@ -64,6 +64,7 @@ namespace iter { return (this->iter1 != rhs.iter1) && (this->iter2 != rhs.iter2); } };*/ + //this specialization commented out template struct zip_iter { From d2940d7a24554e17c1d48da69825a1bc3e5bb6ef Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 7 Oct 2013 22:12:33 -0700 Subject: [PATCH 0064/1866] Shows filter and filter false without predicate in README --- README.md | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1ae99384..17498761 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,15 @@ library. ##### Table of Contents [range](#range)
+[enumerate](#enumerate)
+[zip](#zip)
+[imap](#imap)
[filter](#filter)
[filterfalse](#filterfalse)
[takewhile](#takewhile)
[dropwhile](#dropwhile)
-[enumerate](#enumerate)
[cycle](#cycle)
[compress](#compress)
-[zip](#zip)
-[imap](#imap)
[chain](#chain)
[reverse](#reverse)
[slice](#slice)
@@ -94,26 +94,44 @@ Called as `filter(predicate, iterable)`. The predicate can be any callable. Prints values greater than 4: `5 6 7 8` ```c++ -vector vec{1, 5, 4, 6, 7, 3, 2, 8, 3, 2, 1}; +vector vec{1, 5, 4, 0, 6, 7, 3, 0, 2, 8, 3, 2, 1}; for (auto i : filter([] (int i) { return i > 4; }, vec)) { cout << i <<'\n'; } ``` +If no predicate is passed, the elements themselves are tested for truth + +Prints only non-zero values. +```c++ +for(auto i : filter(vec)) { + cout << i << '\n'; +} +``` + filterfalse ----------- Similar to filter, but only prints values that are false under the predicate. Prints values not greater than 4: `1 4 3 2 3 2 1 ` ```c++ -vector vec{1, 5, 4, 6, 7, 3, 2, 8, 3, 2, 1}; +vector vec{1, 5, 4, 0, 6, 7, 3, 0, 2, 8, 3, 2, 1}; for (auto i : filter([] (int i) { return i > 4; }, vec)) { cout << i <<'\n'; } ``` +If no predicate is passed, the elements themselves are tested for truth. + +Prints only zero values. +```c++ +for(auto i : filterfalse(vec)) { + cout << i << '\n'; +} +``` + takewhile --------- Yields elements from an iterable until the first element that is false under From a9b906e0752e00d55ec5fa0a858a543b96e8e0a6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 7 Oct 2013 22:17:09 -0700 Subject: [PATCH 0065/1866] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 17498761..f6646077 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ CPPItertools range-based for loop add-ons inspired by the python builtins and itertools library. +*Note*: Everthing is inside the `iter` namespace. + ##### Table of Contents [range](#range)
[enumerate](#enumerate)
From e0ff9278004949c7797c23d2f679dffa056849a2 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Tue, 8 Oct 2013 01:19:01 -0400 Subject: [PATCH 0066/1866] Did perfect forwarding in zip_longest --- tests/testzip.cpp | 3 ++- tests/testzip_longest.cpp | 11 +++++++++++ zip_longest.hpp | 12 ++++++------ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/tests/testzip.cpp b/tests/testzip.cpp index 32483d83..25174673 100644 --- a/tests/testzip.cpp +++ b/tests/testzip.cpp @@ -69,9 +69,10 @@ int main() { << std::get<3>(e) << std::endl; } std::cout< constvector{1.1,2.2,3.3,4.4}; for (auto e : zip(std::vector{1,2,3,4,5}, std::initializer_list{"asdfas","aaron","ryan"}, - std::initializer_list{1.1,2.2,3.3,4.4})) { + constvector)) { std::cout << std::get<0>(e) << " " << std::get<1>(e) << " " diff --git a/tests/testzip_longest.cpp b/tests/testzip_longest.cpp index e2fb8aab..c6c0dc59 100644 --- a/tests/testzip_longest.cpp +++ b/tests/testzip_longest.cpp @@ -75,6 +75,17 @@ int main() { << 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< iterator_range> - zip_longest(Containers & ... containers) + zip_longest(Containers && ... containers) { auto begin = - zip_longest_iter(containers...); + zip_longest_iter(std::forward(containers)...); auto end = - zip_longest_iter(containers...); + zip_longest_iter(std::forward(containers)...); return iterator_range(begin,end); } /* @@ -35,7 +35,7 @@ namespace iter { const Iterator end; public: - zip_longest_iter(Container & c) : + zip_longest_iter(Container && c) : begin(c.begin()),end(c.end()) {} std::tuple())>> @@ -69,10 +69,10 @@ namespace iter { std::tuple>(), *inner_iter)); - zip_longest_iter(Container & c, Containers & ... containers) : + zip_longest_iter(Container && c, Containers && ... containers) : begin(c.begin()), end(c.end()), - inner_iter(containers...) {} + inner_iter(std::forward(containers)...) {} //this is for returning a tuple of optional From 3693370054f1ab7b49ebc208b9af9da2a5114b16 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 8 Oct 2013 00:50:54 -0700 Subject: [PATCH 0067/1866] Adds = default for copyctor --- cycle.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cycle.hpp b/cycle.hpp index 9a94921d..a47b87c2 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -35,9 +35,9 @@ namespace iter { Cycle(Container & container) : container(container) { } Cycle () = delete; Cycle & operator=(const Cycle &) = delete; - // Default copy constructor used public: + Cycle(const Cycle &) = default; class Iterator { private: contained_iter_type sub_iter; From 09ddd92603d2974243944169c465b28593549970 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 8 Oct 2013 00:51:27 -0700 Subject: [PATCH 0068/1866] Adds = default for copyctor --- dropwhile.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index ffba1d16..3151d4f6 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -36,9 +36,9 @@ namespace iter { { } DropWhile () = delete; DropWhile & operator=(const DropWhile &) = delete; - // Default copy constructor used public: + DropWhile(const Dropwhile &) = default; class Iterator { private: contained_iter_type sub_iter; From d3306bbf992c951fe84feaaa96e795564a2607c6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 8 Oct 2013 00:54:57 -0700 Subject: [PATCH 0069/1866] Adds = default for copy ctor --- dropwhile.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index 3151d4f6..cf730f0c 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -38,7 +38,7 @@ namespace iter { DropWhile & operator=(const DropWhile &) = delete; public: - DropWhile(const Dropwhile &) = default; + DropWhile(const DropWhile &) = default; class Iterator { private: contained_iter_type sub_iter; From ba245c3f5b850f2e8c5e1c051dd5e566cd8e87ef Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 8 Oct 2013 00:55:04 -0700 Subject: [PATCH 0070/1866] Adds = default for copy ctor --- enumerate.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/enumerate.hpp b/enumerate.hpp index 2c3dad18..7f48a1d9 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -45,9 +45,10 @@ namespace iter { Enumerable(Container & container) : container(container) { } Enumerable () = delete; Enumerable & operator=(const Enumerable &) = delete; - // Default copy constructor used public: + Enumerable(const Enumerable &) = default; + // "yielded" by the Enumerable::Iterator. Has a .index, and a // .element referencing the value yielded by the subiterator class IterYield { From e8a2aca8675e34f8b273ec2dfb776c57397a0cd7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 8 Oct 2013 00:55:18 -0700 Subject: [PATCH 0071/1866] Adds = default for copy ctor --- filter.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/filter.hpp b/filter.hpp index 6e0e4df9..1dc32769 100644 --- a/filter.hpp +++ b/filter.hpp @@ -35,9 +35,10 @@ namespace iter { { } Filter () = delete; Filter & operator=(const Filter &) = delete; - // Default copy constructor used public: + Filter(const Filter &) = default; + class Iterator { protected: contained_iter_type sub_iter; @@ -130,9 +131,9 @@ namespace iter { { } FilterDefault () = delete; FilterDefault & operator=(const FilterDefault &) = delete; - // Default copy constructor used public: + FilterDefault(const FilterDefault &) = default; class Iterator { protected: contained_iter_type sub_iter; From 7cdf5f62d4b4e65545008208b47d1b2c138c211c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 8 Oct 2013 00:55:25 -0700 Subject: [PATCH 0072/1866] Adds = default for copy ctor --- takewhile.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/takewhile.hpp b/takewhile.hpp index 0a1e033d..11123561 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -36,9 +36,10 @@ namespace iter { TakeWhile () = delete; TakeWhile & operator=(const TakeWhile &) = delete; - // Default copy constructor used public: + TakeWhile(const TakeWhile &) = default; + class Iterator { private: contained_iter_type sub_iter; From f9c967cbcba2c11cb750c8ec00662e3be56e2a72 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 8 Oct 2013 01:02:52 -0700 Subject: [PATCH 0073/1866] Adds case for only list passed to filterfalse --- tests/testfilterfalse.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/testfilterfalse.cpp b/tests/testfilterfalse.cpp index 2c1cd3f3..3d6816b9 100644 --- a/tests/testfilterfalse.cpp +++ b/tests/testfilterfalse.cpp @@ -42,5 +42,11 @@ int main() { 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 : filterfalse(vec2)) { + std::cout << i << '\n'; + } + return 0; } From a56e8301e1ea33f5559999947f620be217ec7d54 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 8 Oct 2013 01:03:27 -0700 Subject: [PATCH 0074/1866] Updates filterfalse to work with no predicate --- filterfalse.hpp | 88 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/filterfalse.hpp b/filterfalse.hpp index 578b57c2..feaaab2f 100644 --- a/filterfalse.hpp +++ b/filterfalse.hpp @@ -84,6 +84,94 @@ namespace iter { Container & container) { return FilterFalse(filter_func, container); } + + + //Forward declarations of filterfalseFalseDefault and filterfalse + template + class filterfalseFalseDefault; + + template + filterfalseFalseDefault filterfalse(Container &); + + template + class filterfalseFalseDefault { + protected: + Container & container; + + // The filterfalse function is the only thing allowed to create a + // filterfalseFalseDefault + friend filterfalseFalseDefault filterfalse(Container &); + // Type of the Container::Iterator, but since the name of that + // iterator can be anything, we have to grab it with this + using contained_iter_type = decltype(container.begin()); + + // The type returned when dereferencing the Container::Iterator + using contained_iter_ret = decltype(container.begin().operator*()); + + // Value constructor for use only in the filterfalse function + filterfalseFalseDefault(Container & container) : + container(container) + { } + filterfalseFalseDefault () = delete; + filterfalseFalseDefault & operator=(const filterfalseFalseDefault &) = delete; + + public: + filterfalseFalseDefault(const filterfalseFalseDefault &) = default; + class Iterator { + protected: + contained_iter_type sub_iter; + const contained_iter_type sub_end; + + void skip_passes() { + while (this->sub_iter != this->sub_end + && *this->sub_iter) { + ++this->sub_iter; + } + } + + public: + Iterator (contained_iter_type iter, + contained_iter_type end) : + sub_iter(iter), + sub_end(end) + { + this->skip_passes(); + } + + contained_iter_ret operator*() const { + return *this->sub_iter; + } + + Iterator & operator++() { + ++this->sub_iter; + this->skip_passes(); + return *this; + } + + bool operator!=(const Iterator & other) const { + return this->sub_iter != other.sub_iter; + } + }; + + Iterator begin() const { + return Iterator( + this->container.begin(), + this->container.end()); + } + + Iterator end() const { + return Iterator( + this->container.end(), + this->container.end()); + } + + }; + + // Helper function to instantiate a filterfalseFalseDefault + template + filterfalseFalseDefault filterfalse(Container & container) { + return filterfalseFalseDefault(container); + } } From 36a97a0533767a0fd56e197f24fe68f6dbbb5e59 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 8 Oct 2013 15:47:42 -0700 Subject: [PATCH 0075/1866] Adds environment to SConstruct This looks more like the right way to use scons. Also preserves highlighting from the compiler output to be --- tests/SConstruct | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/tests/SConstruct b/tests/SConstruct index 08eb17de..82f54829 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -1,4 +1,21 @@ import platform +import os + +env = Environment( + CXX='g++', + CXXFLAGS=' -Wall -Wextra -pedantic -std=c++11 -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'] + +# if on MAC, needs the linker flag for -stdlib=libc++ +if platform.system() == 'Darwin': + env['CXX'] += ' -stdlib=libc++ ' + env['CXXFLAGS'] += ' -stdlib=libc++ ' + + progs = Split( ''' cycle @@ -25,16 +42,6 @@ progs = Split( ''' grouper ''') -cxx = 'c++' -cxx_flags = ' -Wall -Wextra -pedantic -std=c++11 -I/usr/local/include' -ldflags = ' -L/usr/local/lib' - -# if on MAC, needs the linker flag for -stdlib=libc++ -if platform.system() == 'Darwin': - ldflags += ' -stdlib=libc++ ' - cxx_flags += ' -stdlib=libc++ ' for p in progs: - Program(source='test{0}.cpp'.format(p), - CXXFLAGS=cxx_flags, CPPPATH='..', CXX=cxx, - LINKFLAGS=ldflags) + env.Program('test{0}.cpp'.format(p)) From 277653eea0e75a656ce3c2bd528758d101026cc9 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Thu, 10 Oct 2013 16:03:37 -0400 Subject: [PATCH 0076/1866] perfect forwarding in slice --- slice.hpp | 4 ++-- tests/testzip.cpp | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/slice.hpp b/slice.hpp index 408645d1..5b65a8a4 100644 --- a/slice.hpp +++ b/slice.hpp @@ -10,7 +10,7 @@ namespace iter { template auto slice( - Container & container, + Container && container, typename std::iterator_traits::difference_type begin, typename std::iterator_traits::difference_type end, typename std::iterator_traits::difference_type step = 1 @@ -39,7 +39,7 @@ namespace iter { //only give the end as an arg and assume step is 1 and begin is 0 template auto slice( - Container & container, + Container && container, typename std::iterator_traits::difference_type end ) -> iterator_range> { diff --git a/tests/testzip.cpp b/tests/testzip.cpp index 25174673..8b168dfa 100644 --- a/tests/testzip.cpp +++ b/tests/testzip.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -70,11 +71,12 @@ int main() { } std::cout< constvector{1.1,2.2,3.3,4.4}; - for (auto e : zip(std::vector{1,2,3,4,5}, - std::initializer_list{"asdfas","aaron","ryan"}, - constvector)) { + for (auto e : zip(iter::chain(std::vector{1,5},std::array{{1,2}}), + std::initializer_list{"asdfas","aaron","ryan","apple","juice"}, + constvector)) + { - std::cout << std::get<0>(e) << " " + std::cout << (std::get<0>(e)=5) << " " << std::get<1>(e) << " " << std::get<2>(e) << std::endl; } From 38490c814ccaa2c5863a6abb203c2524c67638f3 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Thu, 10 Oct 2013 16:08:09 -0400 Subject: [PATCH 0077/1866] perfect forwarding in moving_section and reverse --- moving_section.hpp | 13 +++++++------ reverse.hpp | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/moving_section.hpp b/moving_section.hpp index 35b940bf..e21c2dc8 100644 --- a/moving_section.hpp +++ b/moving_section.hpp @@ -6,30 +6,31 @@ #include #include #include +#include namespace iter { template struct moving_section_iter; template iterator_range> - moving_section(Container & container, size_t s) { - auto begin = moving_section_iter(container,s); - auto end = moving_section_iter(container); + moving_section(Container && container, size_t s) { + auto begin = moving_section_iter(std::forward(container),s); + auto end = moving_section_iter(std::forward(container)); return iterator_range>(begin,end); } template struct moving_section_iter { - Container & container; + Container && container; using Iterator = decltype(container.begin()); std::vector section; size_t section_size = 0; - moving_section_iter(Container & c, size_t s) : + moving_section_iter(Container && c, size_t s) : container(c),section_size(s) { for (size_t i = 0; i < section_size; ++i) section.push_back(container.begin()+i); } - moving_section_iter(Container & c) : container(c) + moving_section_iter(Container && c) : container(c) //creates the end iterator { section.push_back(container.end()); diff --git a/reverse.hpp b/reverse.hpp index fdd8507f..14e8352c 100644 --- a/reverse.hpp +++ b/reverse.hpp @@ -5,7 +5,7 @@ namespace iter { template - auto reverse(Container & container) -> iterator_range + auto reverse(Container && container) -> iterator_range { return iterator_range(container.rbegin(),container.rend()); From 9998d67b87bf939b8fd4fb663d39cc5ebcd9bb10 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Thu, 10 Oct 2013 16:30:01 -0400 Subject: [PATCH 0078/1866] all perfect forwarding added for aarons functions --- grouper.hpp | 17 +++++++++-------- moving_section.hpp | 4 ++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/grouper.hpp b/grouper.hpp index 94273260..e8761647 100644 --- a/grouper.hpp +++ b/grouper.hpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace iter { template @@ -13,16 +14,16 @@ namespace iter { template iterator_range> grouper( - Container & container, size_t s) { - auto begin = grouper_iter(container, s); - auto end = grouper_iter(container); + Container && container, size_t s) { + auto begin = grouper_iter(std::forward(container), s); + auto end = grouper_iter(std::forward(container)); return iterator_range>(begin, end); } template class grouper_iter { private: - Container & container; + Container && container; using Iterator = decltype(container.begin()); using Deref_type = std::vector< @@ -37,8 +38,8 @@ namespace iter { bool not_done = true; public: - grouper_iter(Container & c, size_t s) : - container(c),group_size(s) + grouper_iter(Container && c, size_t s) : + container(std::forward(c)),group_size(s) { // if the group size is 0 or the container is empty produce // nothing @@ -52,8 +53,8 @@ namespace iter { } //seems like conclassor is same as moving_section_iter - grouper_iter(Container & c) : - container(c) + grouper_iter(Container && c) : + container(std::forward(c)) { //creates the end iterator group.push_back(container.end()); diff --git a/moving_section.hpp b/moving_section.hpp index e21c2dc8..f22cc80d 100644 --- a/moving_section.hpp +++ b/moving_section.hpp @@ -26,11 +26,11 @@ namespace iter { std::vector section; size_t section_size = 0; moving_section_iter(Container && c, size_t s) : - container(c),section_size(s) { + container(std::forward(c)),section_size(s) { for (size_t i = 0; i < section_size; ++i) section.push_back(container.begin()+i); } - moving_section_iter(Container && c) : container(c) + moving_section_iter(Container && c) : container(std::forward(c)) //creates the end iterator { section.push_back(container.end()); From 3d1610e1345583e9cc165b4caa99eb1303aaf3b2 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Thu, 10 Oct 2013 16:45:42 -0400 Subject: [PATCH 0079/1866] Added file for testing chaining of itertools functions --- tests/.gitignore | 1 + tests/SConstruct | 1 + tests/testcommand_chains.cpp | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 tests/testcommand_chains.cpp diff --git a/tests/.gitignore b/tests/.gitignore index 450ff7b2..28a3d478 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -22,4 +22,5 @@ testimap testfilterfalse testcount testgrouper +testcommand_chains .sconsign.dblite diff --git a/tests/SConstruct b/tests/SConstruct index 4b61d7fc..57c088cf 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -41,6 +41,7 @@ progs = Split( ''' filterfalse grouper chain + command_chains ''') diff --git a/tests/testcommand_chains.cpp b/tests/testcommand_chains.cpp new file mode 100644 index 00000000..7e59ca62 --- /dev/null +++ b/tests/testcommand_chains.cpp @@ -0,0 +1,34 @@ +#include + +#include +#include +#include +#include +#include + +using namespace iter; + +template +std::ostream & operator<<(std::ostream & o, const boost::optional & opt) { + if (opt) { + std::cout << *opt; + } + else { + std::cout << "Object disengaged of type " << typeid(T).name(); + } + return o; +} + +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; + } + } + return 0; +} From 4c5e187c35ac739275510c6bd056f7688a625d46 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Thu, 10 Oct 2013 17:22:50 -0400 Subject: [PATCH 0080/1866] added another command chaining test --- chain.hpp | 6 +++--- slice.hpp | 2 +- tests/testcommand_chains.cpp | 11 +++++++++++ wrap_iter.hpp | 8 +++++++- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/chain.hpp b/chain.hpp index ad8e3226..4ac309c2 100644 --- a/chain.hpp +++ b/chain.hpp @@ -53,7 +53,7 @@ namespace iter { } chain_iter & operator++() { - if (begin == end) { + if (!(begin != end)) { ++next_iter; } else { @@ -63,7 +63,7 @@ namespace iter { } auto operator*()->decltype(*begin) { - if (begin == end) { + if (!(begin != end)) { return *next_iter; } else { @@ -71,7 +71,7 @@ namespace iter { } } bool operator !=(const chain_iter & rhs) const { - if (begin == end) { + if (!(begin != end)) { return this->next_iter != rhs.next_iter; } else diff --git a/slice.hpp b/slice.hpp index 5b65a8a4..6fb37949 100644 --- a/slice.hpp +++ b/slice.hpp @@ -43,7 +43,7 @@ namespace iter { typename std::iterator_traits::difference_type end ) -> iterator_range> { - return slice(container,0,end); + return slice(std::forward(container),0,end); } } diff --git a/tests/testcommand_chains.cpp b/tests/testcommand_chains.cpp index 7e59ca62..98c6f1ea 100644 --- a/tests/testcommand_chains.cpp +++ b/tests/testcommand_chains.cpp @@ -30,5 +30,16 @@ int main() { << 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}; + 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; + } + } return 0; } diff --git a/wrap_iter.hpp b/wrap_iter.hpp index 2477753b..31bc899b 100644 --- a/wrap_iter.hpp +++ b/wrap_iter.hpp @@ -11,6 +11,7 @@ namespace iter { typename std::iterator_traits::difference_type step; public: + //using difference_type = typename std::iterator_traits::difference_type; wrap_iter(const Iterator & iter, typename std::iterator_traits::difference_type step) : iter(iter), @@ -37,6 +38,11 @@ namespace iter { typename std::iterator_traits::difference_type step) { return wrap_iter(iter,step); } + } - +template + struct std::iterator_traits> { + using difference_type = typename std::iterator_traits::difference_type; + //should add the rest later for a more usable class + }; #endif //WRAP_ITER_HPP__ From a6db8280d41edf22812cc25a0f37fa3613de7271 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 10 Oct 2013 22:42:40 -0700 Subject: [PATCH 0081/1866] Adds test for groupby --- tests/testgroupby.cpp | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tests/testgroupby.cpp diff --git a/tests/testgroupby.cpp b/tests/testgroupby.cpp new file mode 100644 index 00000000..17443343 --- /dev/null +++ b/tests/testgroupby.cpp @@ -0,0 +1,36 @@ +#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'; + } + + + return 0; +} + + From a4eb068cfbd0a13af130b582f1c5759198a6a0fa Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 10 Oct 2013 22:43:04 -0700 Subject: [PATCH 0082/1866] Adds groupby --- groupby.hpp | 183 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 groupby.hpp diff --git a/groupby.hpp b/groupby.hpp new file mode 100644 index 00000000..e21ea30b --- /dev/null +++ b/groupby.hpp @@ -0,0 +1,183 @@ +#ifndef GROUP__BY__HPP +#define GROUP__BY__HPP + + +#include + + +namespace iter { + + template + class GroupBy; + + template + GroupBy groupby(Container &, KeyFunc); + + template + class GroupBy { + private: + Container & container; + KeyFunc key_func; + + // The filter function is the only thing allowed to create a Filter + friend GroupBy groupby(Container &, KeyFunc); + + // Type of the Container::Iterator, but since the name of that + // iterator can be anything, we have to grab it with this + using contained_iter_type = decltype(container.begin()); + + // The type returned when dereferencing the Container::Iterator + using contained_iter_ret = decltype(container.begin().operator*()); + + using key_func_ret = + decltype(std::declval()( + std::declval())); + + GroupBy(Container & container, KeyFunc key_func) : + container(container), + key_func(key_func) + { } + GroupBy () = delete; + GroupBy & operator=(const GroupBy &) = delete; + + public: + GroupBy(const GroupBy &) = default; + + class Iterator; + class Group; + + class Iterator { + private: + contained_iter_type sub_iter; + contained_iter_type sub_iter_peek; + const contained_iter_type sub_end; + KeyFunc key_func; + + using KeyGroupPair = + std::pair; + + public: + Iterator (contained_iter_type si, + contained_iter_type end, + KeyFunc key_func) : + sub_iter(si), + sub_end(end), + key_func(key_func) + { } + + KeyGroupPair operator*() { + return KeyGroupPair( + this->key_func(*this->sub_iter), + Group( + this, + this->key_func(*this->sub_iter))); + } + + Iterator & operator++() { + return *this; + } + + bool operator!=(const Iterator &) const { + return !this->exhausted(); + } + + void increment_iterator() { + if (this->sub_iter != this->sub_end) { + ++this->sub_iter; + } + } + + bool exhausted() const { + return this->sub_iter == this->sub_end; + } + + contained_iter_ret current() const { + return *this->sub_iter; + } + + key_func_ret next_key() const { + return this->key_func(*this->sub_iter); + } + }; + + + class Group { + private: + friend Iterator; + Iterator *owner; + key_func_ret key; + + Group(Iterator *owner, key_func_ret key) : + owner(owner), + key(key) + { } + + + Group () = delete; + public: + Group (const Group &) = default; + + class GroupIterator { + private: + Iterator * owner; + const key_func_ret key; + + public: + GroupIterator(Iterator * owner, key_func_ret key) : + owner(owner), + key(key) + { } + + GroupIterator(const GroupIterator &) = default; + + bool operator!=(const GroupIterator &) const { + return !this->owner->exhausted() && + this->owner->next_key() == this->key; + } + + GroupIterator & operator++() { + this->owner->increment_iterator(); + return *this; + } + + contained_iter_ret operator*() const { + return this->owner->current(); + } + }; + + GroupIterator begin() const { + return GroupIterator(this->owner, key); + } + + GroupIterator end() const { + return GroupIterator(this->owner, key); + } + + }; + + + Iterator begin() const { + return Iterator( + this->container.begin(), + this->container.end(), + this->key_func); + } + + Iterator end() const { + return Iterator( + this->container.end(), + this->container.end(), + this->key_func); + } + + }; + + template + GroupBy groupby( + Container & container, KeyFunc key_func) { + return GroupBy(container, key_func); + } +} + + +#endif //#ifndef GROUP__BY__HPP From 4fbcf61048f3f2344cb63439d6771ac49d48d8a5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 10 Oct 2013 22:43:33 -0700 Subject: [PATCH 0083/1866] Adds groupby to SConstruct --- tests/SConstruct | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/SConstruct b/tests/SConstruct index 4b61d7fc..54aa597e 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -3,7 +3,7 @@ import os env = Environment( CXX='g++', - CXXFLAGS=' -Wall -Wextra -pedantic -std=c++11 -I/usr/local/include', + CXXFLAGS=' -g -Wall -Wextra -pedantic -std=c++11 -I/usr/local/include', CPPPATH='..', LINKFLAGS='-L/usr/local/lib') @@ -41,6 +41,7 @@ progs = Split( ''' filterfalse grouper chain + groupby ''') From 98cde0779147f94431fb14a85afd135edd00c2be Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 10 Oct 2013 22:44:14 -0700 Subject: [PATCH 0084/1866] Adds testgroupby to .gitignore --- tests/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/.gitignore b/tests/.gitignore index 450ff7b2..15ef90c6 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -22,4 +22,5 @@ testimap testfilterfalse testcount testgrouper +testgroupby .sconsign.dblite From b625318c8a1b0742bb69bcc18a075d6f08951e50 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Fri, 11 Oct 2013 14:02:50 -0400 Subject: [PATCH 0085/1866] increased command chaining ability of moving_section --- moving_section.hpp | 14 +++++++++++--- tests/testcommand_chains.cpp | 11 +++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/moving_section.hpp b/moving_section.hpp index f22cc80d..d99c2bc6 100644 --- a/moving_section.hpp +++ b/moving_section.hpp @@ -21,14 +21,22 @@ namespace iter { template struct moving_section_iter { - Container && container; + typename + std::conditional::value, + Container&, + const Container &>::type container; + //Container && container; using Iterator = decltype(container.begin()); std::vector section; size_t section_size = 0; moving_section_iter(Container && c, size_t s) : container(std::forward(c)),section_size(s) { - for (size_t i = 0; i < section_size; ++i) - section.push_back(container.begin()+i); + size_t i = 0; + for (auto iter = container.begin(); i < section_size;++iter,++i) { + section.push_back(iter); + } + //for (size_t i = 0; i < section_size; ++i) + // section.push_back(container.begin()+i); } moving_section_iter(Container && c) : container(std::forward(c)) //creates the end iterator diff --git a/tests/testcommand_chains.cpp b/tests/testcommand_chains.cpp index 98c6f1ea..eaeeb9eb 100644 --- a/tests/testcommand_chains.cpp +++ b/tests/testcommand_chains.cpp @@ -41,5 +41,16 @@ int main() { << 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}; + std::vector strvec + {"We're","done","when","I","say","we're","done"}; + for (auto s : moving_section(chain(vec1,vec2),4)) { + for (auto i : s) std::cout << i << " "; + std::cout< Date: Fri, 11 Oct 2013 17:40:24 -0400 Subject: [PATCH 0086/1866] added increased chainability to grouper --- grouper.hpp | 27 ++++++++++++++++++++++----- itertools.hpp | 1 + tests/testcommand_chains.cpp | 11 +++++++++-- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/grouper.hpp b/grouper.hpp index e8761647..5dc7aab6 100644 --- a/grouper.hpp +++ b/grouper.hpp @@ -23,7 +23,11 @@ namespace iter { template class grouper_iter { private: - Container && container; + typename + std::conditional::value, + Container&, + const Container &>::type container; + //Container && container; using Iterator = decltype(container.begin()); using Deref_type = std::vector< @@ -48,8 +52,12 @@ namespace iter { this->not_done = false; return; } - for (size_t i = 0; i < this->group_size; ++i) - this->group.push_back(this->container.begin() + i); + size_t i = 0; + for (auto iter = container.begin(); i < group_size;++i,++iter) { + group.push_back(iter); + } + //for (size_t i = 0; i < this->group_size; ++i) + // this->group.push_back(this->container.begin() + i); } //seems like conclassor is same as moving_section_iter @@ -60,13 +68,22 @@ namespace iter { group.push_back(container.end()); } + //plan to conditionally check for existence of += + /* + template struct int_{typedef int type;};dd + template ::type = 0> grouper_iter & operator++() { for (auto & iter : this->group) { iter += this->group_size; } return *this; + }*/ + grouper_iter & operator++() { + for (auto & iter : this->group) { + for(size_t i = 0; i < group_size;++i,++iter); + } + return *this; } - bool operator!=(const grouper_iter &) const { return this->not_done; } @@ -74,7 +91,7 @@ namespace iter { Deref_type operator*() { Deref_type vec; for (auto i : this->group) { - if(i == this->container.end()) { + if(!(i != this->container.end())) { this->not_done = false; break; } diff --git a/itertools.hpp b/itertools.hpp index fe40a3e3..e0214b96 100644 --- a/itertools.hpp +++ b/itertools.hpp @@ -25,6 +25,7 @@ #include "zip_longest.hpp" #include "powerset.hpp" #include "moving_section.hpp" +#include "grouper.hpp" //not sure if should include "iterator_range.hpp" //since it's already in everything diff --git a/tests/testcommand_chains.cpp b/tests/testcommand_chains.cpp index eaeeb9eb..7bc48d2d 100644 --- a/tests/testcommand_chains.cpp +++ b/tests/testcommand_chains.cpp @@ -45,12 +45,19 @@ int main() { { 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 s : moving_section(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< Date: Sat, 12 Oct 2013 16:13:17 -0400 Subject: [PATCH 0087/1866] updated iter_ideas --- iter_ideas.txt | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/iter_ideas.txt b/iter_ideas.txt index be6d2b9c..465fe336 100644 --- a/iter_ideas.txt +++ b/iter_ideas.txt @@ -20,3 +20,37 @@ useful if a lot of the containers are of different sizes. may want to write a different zip_get that works better with optional Might be a good idea to do a powerset function + +Recipes: +Not all of the recipes are useful, IMO here are the ones I think we should do + +------------------------------------------------------------------------------ +take(n, range) + +takes first n items from range and turns it into its own list + +------------------------------------------------------------------------------ +quantify(range,predicate) + +return amount of times predicate is true + +------------------------------------------------------------------------------ +def flatten(listoflists) + +flattens one level of nesting +would be tricky in c++ but kinda useful + +------------------------------------------------------------------------------ +roundrobin(Containers ... containers) + +takes the first element off in sequence + +------------------------------------------------------------------------------ +unique_everseen(range) + +only shows unique elements + +------------------------------------------------------------------------------ +unique_justseen(range) + +if multiple are the same in a row only display the first one From 3c3b915dbd8991383ebd9515de46b2f9a77d7f81 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 13 Oct 2013 18:40:40 -0700 Subject: [PATCH 0088/1866] Complete rewrite of filterfalse Tosses the new classes in favor of wrapper function and extra classes to build filterfalse() ontop of filter() --- filterfalse.hpp | 226 ++++++++++++++---------------------------------- 1 file changed, 64 insertions(+), 162 deletions(-) diff --git a/filterfalse.hpp b/filterfalse.hpp index feaaab2f..e24ab9dc 100644 --- a/filterfalse.hpp +++ b/filterfalse.hpp @@ -1,179 +1,81 @@ -#ifndef FILTERFALSE__H__ -#define FILTERFALSE__H__ +#ifndef FILTER_FALSE__HPP__ +#define FILTER_FALSE__HPP__ #include "filter.hpp" namespace iter { - //Forward declarations of FilterFalse and filterfalse - template - class FilterFalse; + namespace detail { - template - FilterFalse filterfalse(FilterFunc, Container &); + // Callable object that reverses the boolean result of another + // callable, taking the object in a Container's iterator + template + class PredicateFlipper { + private: + FilterFunc filter_func; - template - class FilterFalse : public Filter { - // The filterfalse function is the only thing allowed to - // create a FilterFalse - friend FilterFalse filterfalse( - FilterFunc, Container &); - using Base = Filter; - - public: - using Filter::Filter; - - class Iterator { - protected: - typename Base::contained_iter_type sub_iter; - const typename Base::contained_iter_type sub_end; - FilterFunc filter_func; - - // skip every element that is true ender the predicate - void skip_passes() { - while (this->sub_iter != this->sub_end - && this->filter_func(*this->sub_iter)) { - ++this->sub_iter; - } - } - - public: - Iterator (typename Base::contained_iter_type iter, - typename Base::contained_iter_type end, - FilterFunc filter_func) : - sub_iter(iter), - sub_end(end), - filter_func(filter_func) - { - this->skip_passes(); - } - - typename Base::contained_iter_ret operator*() const { - return *this->sub_iter; - } - - Iterator & operator++() { - ++this->sub_iter; - this->skip_passes(); - return *this; - } - - bool operator!=(const Iterator & other) const { - return this->sub_iter != other.sub_iter; - } - }; - - Iterator begin() const { - return Iterator( - this->container.begin(), - this->container.end(), - this->filter_func); - } - - Iterator end() const { - return Iterator( - this->container.end(), - this->container.end(), - this->filter_func); - } - }; + using contained_iter_type = + decltype(std::declval().begin()); + using contained_iter_ret = + decltype(std::declval().operator*()); - template - FilterFalse filterfalse(FilterFunc filter_func, - Container & container) { - return FilterFalse(filter_func, container); - } + public: + PredicateFlipper(FilterFunc filter_func) : + filter_func(filter_func) + { } + PredicateFlipper() = delete; + PredicateFlipper(const PredicateFlipper &) = default; - //Forward declarations of filterfalseFalseDefault and filterfalse - template - class filterfalseFalseDefault; + // Calls the filter_func + bool operator() (const contained_iter_ret item) const { + return !bool(filter_func(item)); + } + }; + + // Reverses the bool() conversion result of anything that supports a + // bool conversion + template + class BoolFlipper { + private: + using contained_iter_type = + decltype(std::declval().begin()); + + using contained_iter_ret = + decltype(std::declval().operator*()); + + public: + BoolFlipper() = default; + BoolFlipper(const BoolFlipper &) = default; + bool operator() (const contained_iter_ret item) const { + return !bool(item); + } + }; - template - filterfalseFalseDefault filterfalse(Container &); - template - class filterfalseFalseDefault { - protected: - Container & container; - - // The filterfalse function is the only thing allowed to create a - // filterfalseFalseDefault - friend filterfalseFalseDefault filterfalse(Container &); - // Type of the Container::Iterator, but since the name of that - // iterator can be anything, we have to grab it with this - using contained_iter_type = decltype(container.begin()); - - // The type returned when dereferencing the Container::Iterator - using contained_iter_ret = decltype(container.begin().operator*()); - - // Value constructor for use only in the filterfalse function - filterfalseFalseDefault(Container & container) : - container(container) - { } - filterfalseFalseDefault () = delete; - filterfalseFalseDefault & operator=(const filterfalseFalseDefault &) = delete; - - public: - filterfalseFalseDefault(const filterfalseFalseDefault &) = default; - class Iterator { - protected: - contained_iter_type sub_iter; - const contained_iter_type sub_end; - - void skip_passes() { - while (this->sub_iter != this->sub_end - && *this->sub_iter) { - ++this->sub_iter; - } - } - - public: - Iterator (contained_iter_type iter, - contained_iter_type end) : - sub_iter(iter), - sub_end(end) - { - this->skip_passes(); - } - - contained_iter_ret operator*() const { - return *this->sub_iter; - } - - Iterator & operator++() { - ++this->sub_iter; - this->skip_passes(); - return *this; - } - - bool operator!=(const Iterator & other) const { - return this->sub_iter != other.sub_iter; - } - }; - - Iterator begin() const { - return Iterator( - this->container.begin(), - this->container.end()); - } - - Iterator end() const { - return Iterator( - this->container.end(), - this->container.end()); - } - - }; - - // Helper function to instantiate a filterfalseFalseDefault - template - filterfalseFalseDefault filterfalse(Container & container) { - return filterfalseFalseDefault(container); } -} + // Creates a PredicateFlipper for the predicate function, which reverses + // 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), container)) { + return filter( + detail::PredicateFlipper(filter_func), + container); + } + // Single argument version, uses a BoolFlipper to reverse the truthiness + // of an object + template + auto filterfalse(Container & container) -> + decltype(filter(detail::BoolFlipper(), container)) { + return filter(detail::BoolFlipper(), container); + } + +} -#endif //ifndef FILTERFALSE__H__ +#endif //#ifndef FILTER_FALSE__HPP__ From a43fa50761b2a3d6836dc982574fb2cd5e815de6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 13 Oct 2013 18:47:08 -0700 Subject: [PATCH 0089/1866] Additional filterfalse tests --- tests/testfilterfalse.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/testfilterfalse.cpp b/tests/testfilterfalse.cpp index 3d6816b9..73a8e5eb 100644 --- a/tests/testfilterfalse.cpp +++ b/tests/testfilterfalse.cpp @@ -17,7 +17,7 @@ class LessThanValue { LessThanValue() = delete; LessThanValue(int v) : compare_val(v) { } - bool operator() (int i) { + bool operator() (int i) const { return i < this->compare_val; } }; @@ -42,11 +42,21 @@ int main() { std::cout << i << '\n'; } - std::cout << "Nonzero ints filter(vec2)\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'; + } + return 0; } From a5941aeb57238327134fa4b1248d706ebf17fe81 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 13 Oct 2013 21:08:11 -0700 Subject: [PATCH 0090/1866] Removes FilterDefault, replaces with BoolTester A callable BoolTester class is passed to the regular Filter class which is just a wrapper to a bool cast. This shortens filter.hpp's logic and duplication greatly. --- filter.hpp | 101 +++++++++++------------------------------------------ 1 file changed, 21 insertions(+), 80 deletions(-) diff --git a/filter.hpp b/filter.hpp index 1dc32769..d41012d4 100644 --- a/filter.hpp +++ b/filter.hpp @@ -96,99 +96,40 @@ namespace iter { }; - // Helper function to instantiate a FilterDefault + // Helper function to instantiate a Filter template Filter filter( FilterFunc filter_func, Container & container) { return Filter(filter_func, container); } - //Forward declarations of FilterDefault and filter - template - class FilterDefault; - - template - FilterDefault filter(Container &); - - template - class FilterDefault { - protected: - Container & container; - - // The filter function is the only thing allowed to create a - // FilterDefault - friend FilterDefault filter(Container &); - // Type of the Container::Iterator, but since the name of that - // iterator can be anything, we have to grab it with this - using contained_iter_type = decltype(container.begin()); + namespace detail { - // The type returned when dereferencing the Container::Iterator - using contained_iter_ret = decltype(container.begin().operator*()); + template + bool boolean_cast(const T & t) { + return bool(t); + } - // Value constructor for use only in the filter function - FilterDefault(Container & container) : - container(container) - { } - FilterDefault () = delete; - FilterDefault & operator=(const FilterDefault &) = delete; + template + class BoolTester { + private: + using contained_iter_ret = + decltype(std::declval().begin().operator*()); - public: - FilterDefault(const FilterDefault &) = default; - class Iterator { - protected: - contained_iter_type sub_iter; - const contained_iter_type sub_end; - - void skip_failures() { - while (this->sub_iter != this->sub_end - && !(*this->sub_iter)) { - ++this->sub_iter; - } - } - - public: - Iterator (contained_iter_type iter, - contained_iter_type end) : - sub_iter(iter), - sub_end(end) - { - this->skip_failures(); - } - - contained_iter_ret operator*() const { - return *this->sub_iter; - } - - Iterator & operator++() { - ++this->sub_iter; - this->skip_failures(); - return *this; - } - - bool operator!=(const Iterator & other) const { - return this->sub_iter != other.sub_iter; - } - }; - - Iterator begin() const { - return Iterator( - this->container.begin(), - this->container.end()); - } - - Iterator end() const { - return Iterator( - this->container.end(), - this->container.end()); - } + public: + bool operator() (const contained_iter_ret item) const { + return bool(item); + } + }; + } - }; - // Helper function to instantiate a FilterDefault template - FilterDefault filter(Container & container) { - return FilterDefault(container); + auto filter(Container & container) -> + decltype(filter(detail::BoolTester(), container)) { + return filter(detail::BoolTester(), container); } + } #endif //ifndef FILTER__H__ From 50a8015f7dadda4bb88f07784dcd8bca34f4e43d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 13 Oct 2013 22:23:15 -0700 Subject: [PATCH 0091/1866] Makes BoolFlipper a subclass of BoolTester In filter.hpp, to remove the repetitive 'using' in the similar classes --- filter.hpp | 2 +- filterfalse.hpp | 11 +++-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/filter.hpp b/filter.hpp index d41012d4..270678e9 100644 --- a/filter.hpp +++ b/filter.hpp @@ -112,7 +112,7 @@ namespace iter { template class BoolTester { - private: + protected: using contained_iter_ret = decltype(std::declval().begin().operator*()); diff --git a/filterfalse.hpp b/filterfalse.hpp index e24ab9dc..65b3179c 100644 --- a/filterfalse.hpp +++ b/filterfalse.hpp @@ -37,17 +37,12 @@ namespace iter { // Reverses the bool() conversion result of anything that supports a // bool conversion template - class BoolFlipper { + class BoolFlipper : public BoolTester { private: - using contained_iter_type = - decltype(std::declval().begin()); - - using contained_iter_ret = - decltype(std::declval().operator*()); + using contained_iter_ret = + typename BoolTester::contained_iter_ret; public: - BoolFlipper() = default; - BoolFlipper(const BoolFlipper &) = default; bool operator() (const contained_iter_ret item) const { return !bool(item); } From 900528d74161d3559e7464012381d9cad06b9c9a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 14 Oct 2013 00:31:05 -0700 Subject: [PATCH 0092/1866] Shortens using-decltype in PredicateFlipper --- filterfalse.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/filterfalse.hpp b/filterfalse.hpp index 65b3179c..34b16180 100644 --- a/filterfalse.hpp +++ b/filterfalse.hpp @@ -14,11 +14,8 @@ namespace iter { private: FilterFunc filter_func; - using contained_iter_type = - decltype(std::declval().begin()); - using contained_iter_ret = - decltype(std::declval().operator*()); + decltype(std::declval().begin().operator*()); public: PredicateFlipper(FilterFunc filter_func) : From 0bf5c7b40426775793da55c3e64293517f9f959d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 14 Oct 2013 00:47:27 -0700 Subject: [PATCH 0093/1866] Chanes private to protected in Filter Since it's not being subclassed anymore. --- filter.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/filter.hpp b/filter.hpp index 270678e9..0b201383 100644 --- a/filter.hpp +++ b/filter.hpp @@ -14,7 +14,7 @@ namespace iter { template class Filter { - protected: + private: Container & container; FilterFunc filter_func; From 3f8cfb3f2a19a1d9eebbbe9bd7378008b7e4817c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 14 Oct 2013 23:00:11 -0700 Subject: [PATCH 0094/1866] Initial version of sorted Yields iterators rather than references. --- sorted.hpp | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 sorted.hpp diff --git a/sorted.hpp b/sorted.hpp new file mode 100644 index 00000000..807ec516 --- /dev/null +++ b/sorted.hpp @@ -0,0 +1,61 @@ +#ifndef SORTED__HPP__ +#define SORTED__HPP__ + +#include +#include + +namespace iter { + + template + class Sorted; + + template + Sorted sorted(Container &); + + template + class Sorted { + private: + friend Sorted sorted(Container &); + + using contained_iter_type = + decltype(std::declval().begin()); + + std::vector sorted_iters; + + Sorted() = delete; + Sorted & operator=(const Sorted &) = delete; + + Sorted(Container & container) { + for (auto iter = container.begin(); + iter != container.end(); + ++iter) { + sorted_iters.push_back(iter); + } + std::sort(sorted_iters.begin(), sorted_iters.end(), + [] (const contained_iter_type & it1, + const contained_iter_type & it2) + { return *it1 < *it2; }); + } + + + public: + Sorted(const Sorted &) = default; + auto begin() const -> decltype(sorted_iters.begin()) { + return sorted_iters.begin(); + } + auto end() const -> decltype(sorted_iters.end()) { + return sorted_iters.end(); + } + + }; + + template + Sorted sorted(Container & container) { + return Sorted(container); + } + +} + + + +#endif //#ifndef SORTED__HPP__ From 981eeab405d92a8e747e017e88b6b04cb9d928d0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 15 Oct 2013 00:47:29 -0700 Subject: [PATCH 0095/1866] Reworks sorted to yield from *iterator Rather than the iterator itself, a wrapper class dereferences the iterator. --- sorted.hpp | 41 ++++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/sorted.hpp b/sorted.hpp index 807ec516..08a3a91d 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -5,7 +5,6 @@ #include namespace iter { - template class Sorted; @@ -22,31 +21,57 @@ namespace iter { std::vector sorted_iters; + using sorted_iter_type = decltype(sorted_iters.begin()); + using contained_iter_ret = + decltype(sorted_iters.begin().operator*().operator*()); + Sorted() = delete; Sorted & operator=(const Sorted &) = delete; Sorted(Container & container) { + // Fill the sorted_iters vector with an iterator to each + // element in the container for (auto iter = container.begin(); iter != container.end(); ++iter) { sorted_iters.push_back(iter); } + + // sort by comparing the elements that the iterators point to std::sort(sorted_iters.begin(), sorted_iters.end(), [] (const contained_iter_type & it1, const contained_iter_type & it2) { return *it1 < *it2; }); } - public: + + // Iterates over a series of Iterators, automatically dereferencing + // them when accessed with operator * + class IteratorIterator : public sorted_iter_type { + public: + IteratorIterator(sorted_iter_type iter) : + sorted_iter_type(iter) + { } + IteratorIterator(const IteratorIterator &) = default; + + // Dereference the current iterator before returning + contained_iter_ret operator*() { + return *sorted_iter_type::operator*(); + } + }; + Sorted(const Sorted &) = default; - auto begin() const -> decltype(sorted_iters.begin()) { - return sorted_iters.begin(); - } - auto end() const -> decltype(sorted_iters.end()) { - return sorted_iters.end(); + + IteratorIterator begin() { + IteratorIterator iteriter(sorted_iters.begin()); + return iteriter; } + IteratorIterator end() { + IteratorIterator iteriter(sorted_iters.end()); + return iteriter; + } }; template @@ -56,6 +81,4 @@ namespace iter { } - - #endif //#ifndef SORTED__HPP__ From 87e3215cdf00c1b75816207a45a8bf1d9ceac66c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 15 Oct 2013 00:54:25 -0700 Subject: [PATCH 0096/1866] Adds testsorted --- tests/testsorted.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 tests/testsorted.cpp diff --git a/tests/testsorted.cpp b/tests/testsorted.cpp new file mode 100644 index 00000000..07d1e7cf --- /dev/null +++ b/tests/testsorted.cpp @@ -0,0 +1,21 @@ +#include + +#include +#include + +using iter::sorted; + +int main() +{ + std::vector vec = {19, 3, 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'; + } + + return 0; +} From 0fc122a10b9c1ca991e0ebb7d41b7df92baf115d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 15 Oct 2013 00:54:55 -0700 Subject: [PATCH 0097/1866] Adds testsorted to gitignore --- tests/.gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/.gitignore b/tests/.gitignore index 1a5a4160..323a4686 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -24,4 +24,6 @@ testcount testgrouper testcommand_chains testgroupby +testsorted .sconsign.dblite + From 2f6ed312e8530029a153ea5ca7207a66a0e21541 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 15 Oct 2013 00:55:33 -0700 Subject: [PATCH 0098/1866] Adds testsorted to SConstruct --- tests/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/SConstruct b/tests/SConstruct index e2cd1986..91a52b9e 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -43,6 +43,7 @@ progs = Split( ''' chain command_chains groupby + sorted ''') From e99af983118f494f6ee1947ff746dce9f02652f4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 17 Oct 2013 02:20:00 -0700 Subject: [PATCH 0099/1866] Replaces g++ with c++ --- tests/SConstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/SConstruct b/tests/SConstruct index 91a52b9e..90ffa6cf 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -2,7 +2,7 @@ import platform import os env = Environment( - CXX='g++', + CXX='c++', CXXFLAGS=' -g -Wall -Wextra -pedantic -std=c++11 -I/usr/local/include', CPPPATH='..', LINKFLAGS='-L/usr/local/lib') From 485e9e894f70bd3c601bf26f120d6a1a67c811e2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 17 Oct 2013 02:22:58 -0700 Subject: [PATCH 0100/1866] Formats zip.hpp --- zip.hpp | 53 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/zip.hpp b/zip.hpp index 1542f92b..5b3374aa 100644 --- a/zip.hpp +++ b/zip.hpp @@ -1,28 +1,35 @@ #ifndef ZIP_HPP #define ZIP_HPP -#include #include "iterator_range.hpp" +#include + namespace iter { template - struct zip_iter; + class zip_iter; + template - auto zip(Containers && ... containers) -> - iterator_range> - { - auto begin = zip_iter(containers.begin()...); - auto end = zip_iter(containers.end()...); - return iterator_range(begin,end); - } - template - struct zip_iter { + auto zip(Containers && ... containers) -> + iterator_range> + { + auto begin = + zip_iter(containers.begin()...); + + auto end = + zip_iter(containers.end()...); + + return iterator_range(begin,end); + } + + template + class zip_iter { private: Iterator iter; public: - using Elem_t = decltype(*iter); + using elem_type = decltype(*iter); zip_iter(const Iterator & i) : iter(i){ } @@ -37,7 +44,8 @@ namespace iter { bool operator!=(const zip_iter & rhs) const { return (this->iter != rhs.iter); } - }; /* + }; +#if 0 template struct zip_iter { @@ -63,18 +71,18 @@ namespace iter { bool operator!=(const zip_iter & rhs) const { return (this->iter1 != rhs.iter1) && (this->iter2 != rhs.iter2); } - };*/ + }; +#endif //this specialization commented out template - struct zip_iter { - + class zip_iter { private: First iter; zip_iter inner_iter; public: - using Elem_t = decltype(*iter); - using tuple_t = + using elem_type = decltype(*iter); + using tuple_type = decltype(std::tuple_cat(std::tie(*iter),*inner_iter)); zip_iter(const First & f, const Rest & ... rest) : @@ -82,19 +90,22 @@ namespace iter { inner_iter(rest...) {} - tuple_t operator*() + tuple_type operator*() { return std::tuple_cat(std::tie(*iter),*inner_iter); } + zip_iter & operator++() { ++iter; ++inner_iter; return *this; } + bool operator!=(const zip_iter & rhs) const { - return (this->iter != rhs.iter) && (this->inner_iter != rhs.inner_iter); + return (this->iter != rhs.iter) && + (this->inner_iter != rhs.inner_iter); } - }; + }; } #endif //ZIP_HPP From 4487fa8ee1ef9a8597c1d9641b0cf430bd78d293 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Sat, 19 Oct 2013 14:58:42 -0400 Subject: [PATCH 0101/1866] added unique_justseen having some trouble creating the return type --- tests/.gitignore | 1 + tests/SConstruct | 1 + tests/testunique_justseen.cpp | 14 ++++++++++++++ unique_justseen.hpp | 28 ++++++++++++++++++++++++++++ 4 files changed, 44 insertions(+) create mode 100644 tests/testunique_justseen.cpp create mode 100644 unique_justseen.hpp diff --git a/tests/.gitignore b/tests/.gitignore index 323a4686..4a4246b2 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -25,5 +25,6 @@ testgrouper testcommand_chains testgroupby testsorted +testunique_justseen .sconsign.dblite diff --git a/tests/SConstruct b/tests/SConstruct index 90ffa6cf..59c81627 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -44,6 +44,7 @@ progs = Split( ''' command_chains groupby sorted + unique_justseen ''') diff --git a/tests/testunique_justseen.cpp b/tests/testunique_justseen.cpp new file mode 100644 index 00000000..23587aa6 --- /dev/null +++ b/tests/testunique_justseen.cpp @@ -0,0 +1,14 @@ +#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 << std::endl; + return 0; +} diff --git a/unique_justseen.hpp b/unique_justseen.hpp new file mode 100644 index 00000000..d7fa6ea0 --- /dev/null +++ b/unique_justseen.hpp @@ -0,0 +1,28 @@ +#ifndef UNIQUE_JUSTSEEN_HPP +#define UNIQUE_JUSTSEEN_HPP + +#include "filter.hpp" +#include +#include + +namespace iter +{ + //this should be self evident but unique_justseen places the requirement + //on the elements in the container have the != operator overloaded + template + auto unique_justseen(Container && container) + -> decltype(filter(std::function(),container)) + { + using elem_t = decltype(container.front()); + auto last = container.begin(); + std::function func = [&last,container](elem_t e) + { + if (last == container.begin())return true; + else return *(++last) != e; + }; + return filter(func, container); + } +} + +#endif //UNIQUE_JUSTSEEN_HPP + From 72950f9f6b36748f9218481f4afd142f6898c295 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Sat, 19 Oct 2013 15:01:35 -0400 Subject: [PATCH 0102/1866] modified git ignore --- tests/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/.gitignore b/tests/.gitignore index 4a4246b2..0609433f 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,4 +1,5 @@ *.o +.*.swp testchain testcycle testenumerate From 9e141c6e343501ac79165c46dbf1946465da6c9e Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Sat, 19 Oct 2013 16:44:33 -0400 Subject: [PATCH 0103/1866] Finished unique_justseen --- tests/.gitignore | 2 +- tests/testunique_justseen.cpp | 4 ++-- unique_justseen.hpp | 16 +++++++++++----- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/tests/.gitignore b/tests/.gitignore index 0609433f..3d258104 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,5 +1,5 @@ *.o -.*.swp +*.swp testchain testcycle testenumerate diff --git a/tests/testunique_justseen.cpp b/tests/testunique_justseen.cpp index 23587aa6..7c1dc44e 100644 --- a/tests/testunique_justseen.cpp +++ b/tests/testunique_justseen.cpp @@ -1,13 +1,13 @@ -#include #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)) { + for (auto i : unique_justseen(v)) { std::cout << i << " "; }std::cout << std::endl; return 0; diff --git a/unique_justseen.hpp b/unique_justseen.hpp index d7fa6ea0..c50ba1e0 100644 --- a/unique_justseen.hpp +++ b/unique_justseen.hpp @@ -4,6 +4,7 @@ #include "filter.hpp" #include #include +#include namespace iter { @@ -11,16 +12,21 @@ namespace iter //on the elements in the container have the != operator overloaded template auto unique_justseen(Container && container) - -> decltype(filter(std::function(),container)) + -> Filter,Container> { using elem_t = decltype(container.front()); auto last = container.begin(); - std::function func = [&last,container](elem_t e) + std::function func = [last,container] (elem_t e) mutable { - if (last == container.begin())return true; - else return *(++last) != e; + if (last == container.begin()) { + return true; + } + else { + return *(++last) != e; + } }; - return filter(func, container); + //return filter(func,std::forward(container)); + return filter(func,std::forward(container)); } } From c30138938df39e7d8f50ed197af2183fe043d082 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Sat, 19 Oct 2013 17:44:59 -0400 Subject: [PATCH 0104/1866] Did unique everseen --- tests/SConstruct | 1 + tests/testunique_everseen.cpp | 29 +++++++++++++++++++++++++++++ unique_everseen.hpp | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 tests/testunique_everseen.cpp create mode 100644 unique_everseen.hpp diff --git a/tests/SConstruct b/tests/SConstruct index 59c81627..d8a46d34 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -45,6 +45,7 @@ progs = Split( ''' groupby sorted unique_justseen + unique_everseen ''') diff --git a/tests/testunique_everseen.cpp b/tests/testunique_everseen.cpp new file mode 100644 index 00000000..0c77a9f7 --- /dev/null +++ b/tests/testunique_everseen.cpp @@ -0,0 +1,29 @@ + +#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; + } + { + //should work same as justseen here + 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; + std::unordered_map map; + [&map]() { + map[70]=true; + std::cout << map[60]; + }(); + } + return 0; +} diff --git a/unique_everseen.hpp b/unique_everseen.hpp new file mode 100644 index 00000000..5e99c9fb --- /dev/null +++ b/unique_everseen.hpp @@ -0,0 +1,33 @@ +#ifndef UNIQUE_EVERSEEN_HPP +#define UNIQUE_EVERSEEN_HPP + +#include "filter.hpp" +#include +#include +#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 + template + auto unique_everseen(Container && container) + -> Filter,Container> + { + using elem_t = decltype(container.front()); + std::unordered_map::type,bool> elem_seen; + std::function func = [elem_seen](elem_t e) mutable + //not sure why but elem seen has to be captured by value + { + if(!elem_seen[e]) { + elem_seen[e] = true; + return true; + } + else return false; + }; + return filter(func,std::forward(container)); + } +} + +#endif //UNIQUE_EVERSEEN_HPP From 8e8ee2ca4884d744386506af42235626a6557c91 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Sun, 20 Oct 2013 00:40:03 -0400 Subject: [PATCH 0105/1866] Fixed comment in unique_everseen --- tests/.gitignore | 1 + tests/testunique_everseen.cpp | 5 ----- unique_everseen.hpp | 3 ++- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/tests/.gitignore b/tests/.gitignore index 3d258104..3daf97d6 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -27,5 +27,6 @@ testcommand_chains testgroupby testsorted testunique_justseen +testunique_everseen .sconsign.dblite diff --git a/tests/testunique_everseen.cpp b/tests/testunique_everseen.cpp index 0c77a9f7..e373a8a3 100644 --- a/tests/testunique_everseen.cpp +++ b/tests/testunique_everseen.cpp @@ -19,11 +19,6 @@ int main() { for (auto i : unique_everseen(v)) { std::cout << i << " "; }std::cout << std::endl; - std::unordered_map map; - [&map]() { - map[70]=true; - std::cout << map[60]; - }(); } return 0; } diff --git a/unique_everseen.hpp b/unique_everseen.hpp index 5e99c9fb..52632636 100644 --- a/unique_everseen.hpp +++ b/unique_everseen.hpp @@ -18,7 +18,8 @@ namespace iter using elem_t = decltype(container.front()); std::unordered_map::type,bool> elem_seen; std::function func = [elem_seen](elem_t e) mutable - //not sure why but elem seen has to be captured by value + //has to be captured by value because it goes out of scope when the + //function returns { if(!elem_seen[e]) { elem_seen[e] = true; From 73c10d2a078beb11dcd958ca960a59a4f97ee116 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 22 Oct 2013 15:19:02 -0700 Subject: [PATCH 0106/1866] Adds test with compare function to testsorted --- tests/testsorted.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/testsorted.cpp b/tests/testsorted.cpp index 07d1e7cf..7abdafc6 100644 --- a/tests/testsorted.cpp +++ b/tests/testsorted.cpp @@ -2,6 +2,7 @@ #include #include +#include using iter::sorted; @@ -17,5 +18,14 @@ int main() std::cout << i << '\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[1] < s2[1]; })) { + std::cout << s << '\n'; + } + + return 0; } From f219bf63a4d55947b9c3777ee2013a5f25f7dbb5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 22 Oct 2013 15:26:39 -0700 Subject: [PATCH 0107/1866] Adds comparison function option to sorted It was a tough decision to make between a comparison function and a key_function. I decided on a comparison function since it's so much more common in c++. Ideally I could support both, but for now I'm setting it as comparison function. --- sorted.hpp | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/sorted.hpp b/sorted.hpp index 08a3a91d..b684ddfe 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -5,16 +5,17 @@ #include namespace iter { - template + template class Sorted; - template - Sorted sorted(Container &); + template + Sorted sorted(Container &, CompareFunc); - template + template class Sorted { private: - friend Sorted sorted(Container &); + friend Sorted + sorted(Container &, CompareFunc); using contained_iter_type = decltype(std::declval().begin()); @@ -28,7 +29,7 @@ namespace iter { Sorted() = delete; Sorted & operator=(const Sorted &) = delete; - Sorted(Container & container) { + Sorted(Container & container, CompareFunc compare_func) { // Fill the sorted_iters vector with an iterator to each // element in the container for (auto iter = container.begin(); @@ -39,13 +40,15 @@ namespace iter { // sort by comparing the elements that the iterators point to std::sort(sorted_iters.begin(), sorted_iters.end(), - [] (const contained_iter_type & it1, + [&] (const contained_iter_type & it1, const contained_iter_type & it2) - { return *it1 < *it2; }); + { return compare_func(*it1, *it2); }); } public: + Sorted(const Sorted &) = default; + // Iterates over a series of Iterators, automatically dereferencing // them when accessed with operator * class IteratorIterator : public sorted_iter_type { @@ -61,8 +64,6 @@ namespace iter { } }; - Sorted(const Sorted &) = default; - IteratorIterator begin() { IteratorIterator iteriter(sorted_iters.begin()); return iteriter; @@ -74,9 +75,25 @@ namespace iter { } }; + template + Sorted sorted( + Container & container, CompareFunc compare_func) { + return Sorted(container, compare_func); + } + template - Sorted sorted(Container & container) { - return Sorted(container); + auto sorted(Container & container) -> + decltype(sorted( + container, + std::less().begin().operator*())>() + )) + { + return sorted( + container, + std::less().begin().operator*())>() + ); } } From 505823fcea46936a8bdd444e7674743d11a481c7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 22 Oct 2013 17:04:25 -0700 Subject: [PATCH 0108/1866] Adds default test for groupby --- tests/testgroupby.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/testgroupby.cpp b/tests/testgroupby.cpp index 17443343..d499e8e8 100644 --- a/tests/testgroupby.cpp +++ b/tests/testgroupby.cpp @@ -29,6 +29,16 @@ int main() 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'; + } + return 0; } From 1069dc558184a00daa49d74ffb6eece6362a436c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 22 Oct 2013 17:04:34 -0700 Subject: [PATCH 0109/1866] Adds default groupby(container) Default creates groups by equivalence of the objects themselves rather than the keys. --- groupby.hpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/groupby.hpp b/groupby.hpp index e21ea30b..c468d83d 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -177,6 +177,25 @@ namespace iter { Container & container, KeyFunc key_func) { return GroupBy(container, key_func); } + + template + class ItemReturner { + private: + using contained_iter_ret = + decltype(std::declval().begin().operator*()); + public: + ItemReturner() = default; + contained_iter_ret operator() (contained_iter_ret item) const { + return item; + } + }; + + template + auto groupby(Container & container) -> + decltype(groupby(container, ItemReturner())) { + return groupby(container, ItemReturner()); + } + } From a5598cfacb8836c984b31880b0a7eea272b070ab Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 23 Oct 2013 12:20:45 -0700 Subject: [PATCH 0110/1866] Adds -Weffc++ flag to compilation flags --- tests/SConstruct | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/SConstruct b/tests/SConstruct index d8a46d34..c3c57fa9 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -3,7 +3,9 @@ import os env = Environment( CXX='c++', - CXXFLAGS=' -g -Wall -Wextra -pedantic -std=c++11 -I/usr/local/include', + CXXFLAGS= ['-g', '-Wall', '-Wextra', '-Weffc++', + '-pedantic', '-std=c++11', + '-I/usr/local/include'], CPPPATH='..', LINKFLAGS='-L/usr/local/lib') @@ -12,8 +14,8 @@ env['ENV']['TERM'] = os.environ['TERM'] # if on MAC, needs the linker flag for -stdlib=libc++ if platform.system() == 'Darwin': - env['CXX'] += ' -stdlib=libc++ ' - env['CXXFLAGS'] += ' -stdlib=libc++ ' + env['CXX'] += '-stdlib=libc++' + env['CXXFLAGS'].append('-stdlib=libc++') From 4c8dab34631e9e705fa8f903982325cc1498e415 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 6 Nov 2013 10:49:24 -0500 Subject: [PATCH 0111/1866] Adds iterbase for the common using=s --- iterbase.hpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 iterbase.hpp diff --git a/iterbase.hpp b/iterbase.hpp new file mode 100644 index 00000000..bc499e09 --- /dev/null +++ b/iterbase.hpp @@ -0,0 +1,26 @@ +#ifndef ITERBASE__HPP__ +#define ITERBASE__HPP__ + +#include +#include + +namespace iter { + template + class IterBase{ + protected: + // Type of the Container::Iterator, but since the name of that + // iterator can be anything, we have to grab it with this + using contained_iter_type = + decltype(std::begin(std::declval())); + + // The type returned when dereferencing the Container::Iterator + using contained_iter_ret = + decltype(std::declval().operator*()); + + IterBase() = default; + IterBase(const IterBase &) = default; + IterBase & operator=(const IterBase &) = delete; + }; +} + +#endif // #ifndef ITERBASE__HPP__ From 5968509b39ca303b9604e17b23a855939e852bdd Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 6 Nov 2013 10:50:01 -0500 Subject: [PATCH 0112/1866] Enumerable inherits from IterBase --- enumerate.hpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 7f48a1d9..3fdf3631 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -1,6 +1,8 @@ #ifndef ENUMERABLE__H__ #define ENUMERABLE__H__ +#include "iterbase.hpp" + #include @@ -24,21 +26,28 @@ namespace iter { template - class Enumerable { + class Enumerable : public IterBase{ private: Container & container; // The only thing allowed to directly instantiate an Enumerable is // the enumerate function friend Enumerable enumerate(Container &); + using contained_iter_type = + typename IterBase::contained_iter_type; + + using contained_iter_ret = + typename IterBase::contained_iter_ret; +#if 0 // Type of the Container::Iterator, but since the name of that // iterator can be anything, we have to grab it with this - using contained_iter_type = + //using contained_iter_type = decltype(container.begin()); // The type returned when dereferencing the Container::Iterator using contained_iter_ret = decltype(container.begin().operator*()); +#endif // Value constructor for use only in the enumerate function From 7920666a72c61ec3cf15a66e1249fe63c50cc5b1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 6 Nov 2013 10:59:28 -0500 Subject: [PATCH 0113/1866] Switches .operator* for * to work with pointers Where there was something like decltype(t.operator*()), there is now decltype(*t). This is for working with static arrays where the iterator is a pointer rather than an iterator object. --- iterbase.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iterbase.hpp b/iterbase.hpp index bc499e09..69cfe0c6 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -15,7 +15,7 @@ namespace iter { // The type returned when dereferencing the Container::Iterator using contained_iter_ret = - decltype(std::declval().operator*()); + decltype(*std::declval()); IterBase() = default; IterBase(const IterBase &) = default; From feaff39d3fed6b20517377d7b5a6441be9e9a577 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 6 Nov 2013 11:03:10 -0500 Subject: [PATCH 0114/1866] Switches .begin()/.end() with std::begin/std::end --- enumerate.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 3fdf3631..f2875167 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -98,11 +98,11 @@ namespace iter { }; Iterator begin() const { - return Iterator(this->container.begin()); + return Iterator(std::begin(this->container)); } Iterator end() const { - return Iterator(this->container.end()); + return Iterator(std::end(this->container)); } }; From b9a3122b42e6a6fdfaee4cac5159b219fd8dcd80 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 6 Nov 2013 11:09:48 -0500 Subject: [PATCH 0115/1866] Removes old usings, replaced with base class usings --- enumerate.hpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index f2875167..cec188f7 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -38,16 +38,6 @@ namespace iter { using contained_iter_ret = typename IterBase::contained_iter_ret; -#if 0 - // Type of the Container::Iterator, but since the name of that - // iterator can be anything, we have to grab it with this - //using contained_iter_type = - decltype(container.begin()); - - // The type returned when dereferencing the Container::Iterator - using contained_iter_ret = - decltype(container.begin().operator*()); -#endif // Value constructor for use only in the enumerate function From 260316f8f1a1f67794e519ea0b953a7a34efb83d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 6 Nov 2013 11:18:45 -0500 Subject: [PATCH 0116/1866] Counts in testcycle to only loop 100 times --- tests/testcycle.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/testcycle.cpp b/tests/testcycle.cpp index dc375d8d..0e38a5ae 100644 --- a/tests/testcycle.cpp +++ b/tests/testcycle.cpp @@ -6,13 +6,15 @@ using iter::cycle; int main() { - std::vector vec; - vec.push_back(2); - vec.push_back(4); - vec.push_back(6); + std::vector vec = {2, 4, 6}; + size_t count = 0; for (auto i : cycle(vec)) { std::cout << i << '\n'; + if (count == 100) { + break; + } + ++count; } return 0; From 05a63104731f38e3084bdc9cc212420578ae13c3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 6 Nov 2013 11:20:22 -0500 Subject: [PATCH 0117/1866] Adds static array test for enumerate --- tests/testenumerate.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/testenumerate.cpp b/tests/testenumerate.cpp index d8f4f34c..faebd71f 100644 --- a/tests/testenumerate.cpp +++ b/tests/testenumerate.cpp @@ -26,5 +26,10 @@ int main() { std::cout << e.index << ": " << e.element << std::endl; } + int array[] = {1, 9, 8, 11}; + for (auto e : enumerate(array)) { + std::cout << e.index << ": " << e.element << '\n'; + } + return 0; } From cdbdafc3d3bd928c7419d571f042b0c888763a25 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 6 Nov 2013 11:20:52 -0500 Subject: [PATCH 0118/1866] Adds static array test for cycle --- tests/testcycle.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/testcycle.cpp b/tests/testcycle.cpp index 0e38a5ae..bd4e2d0b 100644 --- a/tests/testcycle.cpp +++ b/tests/testcycle.cpp @@ -17,5 +17,15 @@ int main() { ++count; } + count = 0; + int array[] = {68, 69, 70}; + for (auto i : cycle(array)) { + std::cout << i << '\n'; + if (count == 100) { + break; + } + ++count; + } + return 0; } From dbdff7ae2b02c59fb02ecf70d52f8e19ab7af6da Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 6 Nov 2013 11:21:59 -0500 Subject: [PATCH 0119/1866] Updates cycle for static arrays --- cycle.hpp | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/cycle.hpp b/cycle.hpp index a47b87c2..0ed0e72c 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -1,6 +1,8 @@ #ifndef CYCLE__H__ #define CYCLE__H__ +#include "iterbase.hpp" + #include namespace iter { @@ -14,21 +16,17 @@ namespace iter { template - class Cycle { - // The cycle function is the only thing allowed to create a Cycle - friend Cycle cycle(Container &); - + class Cycle : public IterBase{ + private: + // The cycle function is the only thing allowed to create a Cycle + friend Cycle cycle(Container &); - // Type of the Container::Iterator, but since the name of that - // iterator can be anything, we have to grab it with this - using contained_iter_type = - decltype(std::declval().begin()); + using contained_iter_type = + typename IterBase::contained_iter_type; - // The type returned when dereferencing the Container::Iterator - using contained_iter_ret = - decltype(std::declval().operator*()); + using contained_iter_ret = + typename IterBase::contained_iter_ret; - private: Container & container; // Value constructor for use only in the cycle function @@ -70,12 +68,13 @@ namespace iter { }; Iterator begin() const { - return Iterator(this->container.begin(), - this->container.end()); + return Iterator(std::begin(this->container), + std::end(this->container)); } Iterator end() const { - return Iterator(this->container.end(), this->container.end()); + return Iterator(std::end(this->container), + std::end(this->container)); } }; From 483bb266f9287141e9ad82ed3939028a8e38dfa6 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Wed, 6 Nov 2013 17:33:52 -0500 Subject: [PATCH 0120/1866] std::begin and std::end support --- chain.hpp | 17 ++++++++++------- tests/SConstruct | 4 +++- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/chain.hpp b/chain.hpp index 4ac309c2..669e695b 100644 --- a/chain.hpp +++ b/chain.hpp @@ -3,6 +3,7 @@ #include "iterator_range.hpp" #include +#include namespace iter { template @@ -11,14 +12,15 @@ namespace iter { struct chain_iter { private: - using Iterator = decltype(std::declval().begin()); + //using Iterator = decltype(std::declval().begin()); + using Iterator = decltype(std::begin(std::declval())); Iterator begin; const Iterator end;//never really used but kept it for consistency public: chain_iter(Container && container, bool is_end=false) : - begin(container.begin()),end(container.end()) { - if(is_end) begin = container.end(); + begin(std::begin(container)),end(std::end(container)) { + if(is_end) begin = std::end(container); } chain_iter & operator++() { @@ -37,7 +39,8 @@ namespace iter { struct chain_iter { private: - using Iterator = decltype(std::declval().begin()); + //using Iterator = decltype(std::declval().begin()); + using Iterator = decltype(std::begin(std::declval())); Iterator begin; const Iterator end; bool end_reached = false; @@ -45,11 +48,11 @@ namespace iter { public: chain_iter(Container && container, Containers&& ... containers, bool is_end=false) : - begin(container.begin()), - end(container.end()), + begin(std::begin(container)), + end(std::end(container)), next_iter(std::forward(containers)...,is_end) { if(is_end) - begin = container.end(); + begin = std::end(container); } chain_iter & operator++() { diff --git a/tests/SConstruct b/tests/SConstruct index c3c57fa9..8c300998 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -13,9 +13,11 @@ env = Environment( env['ENV']['TERM'] = os.environ['TERM'] # if on MAC, needs the linker flag for -stdlib=libc++ -if platform.system() == 'Darwin': +# obselete with mavericks +""" if platform.system() == 'Darwin': env['CXX'] += '-stdlib=libc++' env['CXXFLAGS'].append('-stdlib=libc++') +""" From 49f1ce0d1e7eb22a42e25f7ce2652c61332679e0 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Wed, 6 Nov 2013 17:42:59 -0500 Subject: [PATCH 0121/1866] moving section updated for std::begin and std::end --- moving_section.hpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/moving_section.hpp b/moving_section.hpp index d99c2bc6..36ce2906 100644 --- a/moving_section.hpp +++ b/moving_section.hpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace iter { template @@ -26,13 +27,14 @@ namespace iter { Container&, const Container &>::type container; //Container && container; - using Iterator = decltype(container.begin()); + //using Iterator = decltype(container.begin()); + using Iterator = decltype(std::begin(container)); std::vector section; size_t section_size = 0; moving_section_iter(Container && c, size_t s) : container(std::forward(c)),section_size(s) { size_t i = 0; - for (auto iter = container.begin(); i < section_size;++iter,++i) { + for (auto iter = std::begin(container); i < section_size;++iter,++i) { section.push_back(iter); } //for (size_t i = 0; i < section_size; ++i) @@ -41,7 +43,7 @@ namespace iter { moving_section_iter(Container && c) : container(std::forward(c)) //creates the end iterator { - section.push_back(container.end()); + section.push_back(std::end(container)); } moving_section_iter & operator++() { From 01128fc77fb9eb1836b6ea3498438f9fc4eef4c4 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Wed, 6 Nov 2013 17:49:27 -0500 Subject: [PATCH 0122/1866] zip and zip_longest updated for std::begin and std::end --- tests/testzip.cpp | 2 +- zip.hpp | 7 ++++--- zip_longest.hpp | 11 ++++++----- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/tests/testzip.cpp b/tests/testzip.cpp index 8b168dfa..ea30599a 100644 --- a/tests/testzip.cpp +++ b/tests/testzip.cpp @@ -76,7 +76,7 @@ int main() { constvector)) { - std::cout << (std::get<0>(e)=5) << " " + std::cout << std::get<0>(e) << " " << std::get<1>(e) << " " << std::get<2>(e) << std::endl; } diff --git a/zip.hpp b/zip.hpp index 5b3374aa..0f1bff07 100644 --- a/zip.hpp +++ b/zip.hpp @@ -4,6 +4,7 @@ #include "iterator_range.hpp" #include +#include namespace iter { template @@ -11,13 +12,13 @@ namespace iter { template auto zip(Containers && ... containers) -> - iterator_range> + iterator_range> { auto begin = - zip_iter(containers.begin()...); + zip_iter(std::begin(containers)...); auto end = - zip_iter(containers.end()...); + zip_iter(std::end(containers)...); return iterator_range(begin,end); } diff --git a/zip_longest.hpp b/zip_longest.hpp index b2036dba..1ee30fff 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "iterator_range.hpp" namespace iter { @@ -29,14 +30,14 @@ namespace iter { template struct zip_longest_iter { public: - using Iterator = decltype(std::declval().begin()); + using Iterator = decltype(std::begin(std::declval())); private: Iterator begin; const Iterator end; public: zip_longest_iter(Container && c) : - begin(c.begin()),end(c.end()) {} + begin(std::begin(c)),end(std::end(c)) {} std::tuple())>> operator*() @@ -56,7 +57,7 @@ namespace iter { template struct zip_longest_iter { public: - using Iterator = decltype(std::declval().begin()); + using Iterator = decltype(std::begin(std::declval())); private: Iterator begin; const Iterator end; @@ -70,8 +71,8 @@ namespace iter { *inner_iter)); zip_longest_iter(Container && c, Containers && ... containers) : - begin(c.begin()), - end(c.end()), + begin(std::begin(c)), + end(std::end(c)), inner_iter(std::forward(containers)...) {} //this is for returning a tuple of optional From f49484697e38a5c741e57adff5c2a723d6e5bcb4 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Wed, 6 Nov 2013 20:33:51 -0500 Subject: [PATCH 0123/1866] updated grouper to support std::begin and std::end --- grouper.hpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/grouper.hpp b/grouper.hpp index 5dc7aab6..ce9e4871 100644 --- a/grouper.hpp +++ b/grouper.hpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace iter { template @@ -28,7 +29,8 @@ namespace iter { Container&, const Container &>::type container; //Container && container; - using Iterator = decltype(container.begin()); + //using Iterator = decltype(container.begin()); + using Iterator = decltype(std::begin(container)); using Deref_type = std::vector< std::reference_wrapper< @@ -48,12 +50,12 @@ namespace iter { // if the group size is 0 or the container is empty produce // nothing if (this->group_size == 0 || - !(this->container.begin() != this->container.end())) { + !(std::begin(this->container) != std::end(this->container))) { this->not_done = false; return; } size_t i = 0; - for (auto iter = container.begin(); i < group_size;++i,++iter) { + for (auto iter = std::begin(container); i < group_size;++i,++iter) { group.push_back(iter); } //for (size_t i = 0; i < this->group_size; ++i) @@ -65,7 +67,7 @@ namespace iter { container(std::forward(c)) { //creates the end iterator - group.push_back(container.end()); + group.push_back(std::end(container)); } //plan to conditionally check for existence of += @@ -91,7 +93,7 @@ namespace iter { Deref_type operator*() { Deref_type vec; for (auto i : this->group) { - if(!(i != this->container.end())) { + if(!(i != std::end(this->container))) { this->not_done = false; break; } From fc3661520527921d5425ada8656ab20fdc12bd0f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 6 Nov 2013 22:16:22 -0500 Subject: [PATCH 0124/1866] Shortens using baseclass type --- enumerate.hpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index cec188f7..9bd871e9 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -33,11 +33,9 @@ namespace iter { // the enumerate function friend Enumerable enumerate(Container &); - using contained_iter_type = - typename IterBase::contained_iter_type; + using typename IterBase::contained_iter_type; - using contained_iter_ret = - typename IterBase::contained_iter_ret; + using typename IterBase::contained_iter_ret; // Value constructor for use only in the enumerate function From 25063a4b79632c65bc7f6060c49d320bfec6d0f7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 6 Nov 2013 22:19:32 -0500 Subject: [PATCH 0125/1866] Shortens using baseclass type --- cycle.hpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cycle.hpp b/cycle.hpp index 0ed0e72c..6a8eb713 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -21,11 +21,9 @@ namespace iter { // The cycle function is the only thing allowed to create a Cycle friend Cycle cycle(Container &); - using contained_iter_type = - typename IterBase::contained_iter_type; + using typename IterBase::contained_iter_type; - using contained_iter_ret = - typename IterBase::contained_iter_ret; + using typename IterBase::contained_iter_ret; Container & container; From 727940a1396fb44670e1127b1c9c917426d7a1d8 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Wed, 6 Nov 2013 23:25:19 -0500 Subject: [PATCH 0126/1866] used std::advance to make functions more versatile --- grouper.hpp | 9 ++++----- tests/testcommand_chains.cpp | 2 ++ wrap_iter.hpp | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/grouper.hpp b/grouper.hpp index ce9e4871..5e57b2c8 100644 --- a/grouper.hpp +++ b/grouper.hpp @@ -71,21 +71,20 @@ namespace iter { } //plan to conditionally check for existence of += - /* - template struct int_{typedef int type;};dd - template ::type = 0> grouper_iter & operator++() { for (auto & iter : this->group) { - iter += this->group_size; + std::advance(iter,this->group_size); } return *this; - }*/ + } + /* grouper_iter & operator++() { for (auto & iter : this->group) { for(size_t i = 0; i < group_size;++i,++iter); } return *this; } + */ bool operator!=(const grouper_iter &) const { return this->not_done; } diff --git a/tests/testcommand_chains.cpp b/tests/testcommand_chains.cpp index 7bc48d2d..e5c5ece6 100644 --- a/tests/testcommand_chains.cpp +++ b/tests/testcommand_chains.cpp @@ -50,6 +50,7 @@ int main() { std::cout< vec1{1,2,3,4,5,6}; @@ -59,5 +60,6 @@ int main() { std::cout< Date: Thu, 7 Nov 2013 01:28:09 -0500 Subject: [PATCH 0127/1866] big fix on slice, uses std::begin and uses std::advance --- slice.hpp | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/slice.hpp b/slice.hpp index 6fb37949..f0f2dcf6 100644 --- a/slice.hpp +++ b/slice.hpp @@ -11,28 +11,39 @@ namespace iter { template auto slice( Container && container, - typename std::iterator_traits::difference_type begin, - typename std::iterator_traits::difference_type end, - typename std::iterator_traits::difference_type step = 1 - ) -> iterator_range> + typename std::iterator_traits::difference_type begin, + typename std::iterator_traits::difference_type end, + typename std::iterator_traits::difference_type step = 1 + ) -> iterator_range> { //it seems like you can handle negative and positive ranges the same + //kept both checks to make checking for invalid slice more readable if (begin > end && step < 0) { - typename std::iterator_traits::difference_type new_end = end - ((end - begin) % step); - return iterator_range>( - make_wrap_iter(container.begin()+begin,step), - make_wrap_iter(container.begin()+new_end,step)); + typename std::iterator_traits::difference_type new_end = end - ((end - begin) % step); + auto begin_iter = std::begin(container); + std::advance(begin_iter,begin); + auto end_iter = std::begin(container); + std::advance(end_iter,new_end); + return iterator_range>( + make_wrap_iter(begin_iter,step), + make_wrap_iter(end_iter,step)); } else if (begin <= end && step > 0) { typename std::iterator_traits::difference_type new_end = end - ((end - begin) % step); + auto begin_iter = std::begin(container); + std::advance(begin_iter,begin); + auto end_iter = std::begin(container); + std::advance(end_iter,new_end); return iterator_range>( - make_wrap_iter(container.begin()+begin,step), - make_wrap_iter(container.begin()+new_end,step)); + make_wrap_iter(begin_iter,step), + make_wrap_iter(end_iter,step)); } else {//return an empty range for invalid slice + auto empty = std::begin(container); + std::advance(empty,begin); return iterator_range>( - make_wrap_iter(container.begin()+begin,step), - make_wrap_iter(container.begin()+begin,step)); + make_wrap_iter(empty,step), + make_wrap_iter(empty,step)); } } @@ -40,8 +51,8 @@ namespace iter { template auto slice( Container && container, - typename std::iterator_traits::difference_type end - ) -> iterator_range> + typename std::iterator_traits::difference_type end + ) -> iterator_range> { return slice(std::forward(container),0,end); } From d6948c38fec0e66728edc20f86566dccfa35225d Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Thu, 7 Nov 2013 02:26:43 -0500 Subject: [PATCH 0128/1866] added iterator_traits specialization for chain (could very well be illegal c++ IDC) --- chain.hpp | 7 ++++++- tests/testcommand_chains.cpp | 2 -- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/chain.hpp b/chain.hpp index 669e695b..b360485a 100644 --- a/chain.hpp +++ b/chain.hpp @@ -81,6 +81,7 @@ namespace iter { return this->begin != rhs.begin; } }; + template iterator_range> chain(Containers&& ... containers) { @@ -92,5 +93,9 @@ namespace iter { iterator_range>(begin,end); } } - +template +struct std::iterator_traits> { + using difference_type = std::ptrdiff_t; + using iterator_category = std::input_iterator_tag; +}; #endif //CHAIN_HPP diff --git a/tests/testcommand_chains.cpp b/tests/testcommand_chains.cpp index e5c5ece6..7bc48d2d 100644 --- a/tests/testcommand_chains.cpp +++ b/tests/testcommand_chains.cpp @@ -50,7 +50,6 @@ int main() { std::cout< vec1{1,2,3,4,5,6}; @@ -60,6 +59,5 @@ int main() { std::cout< Date: Thu, 7 Nov 2013 10:14:54 -0500 Subject: [PATCH 0129/1866] Replaces a few .begin()s with std::begin --- slice.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/slice.hpp b/slice.hpp index f0f2dcf6..b3494bd7 100644 --- a/slice.hpp +++ b/slice.hpp @@ -29,19 +29,19 @@ namespace iter { make_wrap_iter(end_iter,step)); } else if (begin <= end && step > 0) { - typename std::iterator_traits::difference_type new_end = end - ((end - begin) % step); + typename std::iterator_traits::difference_type new_end = end - ((end - begin) % step); auto begin_iter = std::begin(container); std::advance(begin_iter,begin); auto end_iter = std::begin(container); std::advance(end_iter,new_end); - return iterator_range>( + return iterator_range>( make_wrap_iter(begin_iter,step), make_wrap_iter(end_iter,step)); } else {//return an empty range for invalid slice auto empty = std::begin(container); std::advance(empty,begin); - return iterator_range>( + return iterator_range>( make_wrap_iter(empty,step), make_wrap_iter(empty,step)); } From 5e5c4b0423053c16df5c01a724be1621805ae1ff Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 7 Nov 2013 10:15:40 -0500 Subject: [PATCH 0130/1866] Error missing ) in last commit --- slice.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slice.hpp b/slice.hpp index b3494bd7..d6d41e74 100644 --- a/slice.hpp +++ b/slice.hpp @@ -41,7 +41,7 @@ namespace iter { else {//return an empty range for invalid slice auto empty = std::begin(container); std::advance(empty,begin); - return iterator_range>( + return iterator_range>( make_wrap_iter(empty,step), make_wrap_iter(empty,step)); } From f1af4f4d8d805f9ebe2c5d460cb0903659f7e989 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 7 Nov 2013 10:16:26 -0500 Subject: [PATCH 0131/1866] Replaces assert.h with cassert --- slice.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slice.hpp b/slice.hpp index d6d41e74..f2f8b81e 100644 --- a/slice.hpp +++ b/slice.hpp @@ -5,7 +5,7 @@ #include "wrap_iter.hpp" #include -#include +#include namespace iter { template From b946cf0794f5076820f6549758fdfb08d04d9f97 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 7 Nov 2013 10:30:26 -0500 Subject: [PATCH 0132/1866] Indetation adjustments --- slice.hpp | 88 +++++++++++++++++++++++++++---------------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/slice.hpp b/slice.hpp index f2f8b81e..9131cbf0 100644 --- a/slice.hpp +++ b/slice.hpp @@ -9,53 +9,53 @@ namespace iter { template - auto slice( - Container && container, - typename std::iterator_traits::difference_type begin, - typename std::iterator_traits::difference_type end, - typename std::iterator_traits::difference_type step = 1 - ) -> iterator_range> - { - //it seems like you can handle negative and positive ranges the same - //kept both checks to make checking for invalid slice more readable - if (begin > end && step < 0) { - typename std::iterator_traits::difference_type new_end = end - ((end - begin) % step); - auto begin_iter = std::begin(container); - std::advance(begin_iter,begin); - auto end_iter = std::begin(container); - std::advance(end_iter,new_end); - return iterator_range>( - make_wrap_iter(begin_iter,step), - make_wrap_iter(end_iter,step)); - } - else if (begin <= end && step > 0) { - typename std::iterator_traits::difference_type new_end = end - ((end - begin) % step); - auto begin_iter = std::begin(container); - std::advance(begin_iter,begin); - auto end_iter = std::begin(container); - std::advance(end_iter,new_end); - return iterator_range>( - make_wrap_iter(begin_iter,step), - make_wrap_iter(end_iter,step)); - } - else {//return an empty range for invalid slice - auto empty = std::begin(container); - std::advance(empty,begin); - return iterator_range>( - make_wrap_iter(empty,step), - make_wrap_iter(empty,step)); - } - + auto slice( + Container && container, + typename std::iterator_traits::difference_type begin, + typename std::iterator_traits::difference_type end, + typename std::iterator_traits::difference_type step = 1 + ) -> iterator_range> + { + //it seems like you can handle negative and positive ranges the same + //kept both checks to make checking for invalid slice more readable + if (begin > end && step < 0) { + typename std::iterator_traits::difference_type new_end = end - ((end - begin) % step); + auto begin_iter = std::begin(container); + std::advance(begin_iter,begin); + auto end_iter = std::begin(container); + std::advance(end_iter,new_end); + return iterator_range>( + make_wrap_iter(begin_iter,step), + make_wrap_iter(end_iter,step)); + } + else if (begin <= end && step > 0) { + typename std::iterator_traits::difference_type new_end = end - ((end - begin) % step); + auto begin_iter = std::begin(container); + std::advance(begin_iter,begin); + auto end_iter = std::begin(container); + std::advance(end_iter,new_end); + return iterator_range>( + make_wrap_iter(begin_iter,step), + make_wrap_iter(end_iter,step)); + } + else {//return an empty range for invalid slice + auto empty = std::begin(container); + std::advance(empty,begin); + return iterator_range>( + make_wrap_iter(empty,step), + make_wrap_iter(empty,step)); } + + } //only give the end as an arg and assume step is 1 and begin is 0 template - auto slice( - Container && container, - typename std::iterator_traits::difference_type end - ) -> iterator_range> - { - return slice(std::forward(container),0,end); - } + auto slice( + Container && container, + typename std::iterator_traits::difference_type end + ) -> iterator_range> + { + return slice(std::forward(container),0,end); + } } From 72b277ff917fb971b352a2d0e338e4bf4438a5b9 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Thu, 7 Nov 2013 15:01:45 -0500 Subject: [PATCH 0133/1866] iterator_traits fix in wrap_iter --- slice.hpp | 2 ++ wrap_iter.hpp | 1 + 2 files changed, 3 insertions(+) diff --git a/slice.hpp b/slice.hpp index 9131cbf0..403450e2 100644 --- a/slice.hpp +++ b/slice.hpp @@ -41,6 +41,8 @@ namespace iter { else {//return an empty range for invalid slice auto empty = std::begin(container); std::advance(empty,begin); + //just in case it gets dereferenced it will be the first element had + //the range been valid return iterator_range>( make_wrap_iter(empty,step), make_wrap_iter(empty,step)); diff --git a/wrap_iter.hpp b/wrap_iter.hpp index f21edbb9..1161a393 100644 --- a/wrap_iter.hpp +++ b/wrap_iter.hpp @@ -43,6 +43,7 @@ namespace iter { template struct std::iterator_traits> { using difference_type = typename std::iterator_traits::difference_type; + using iterator_category = typename std::iterator_traits::iterator_category; //should add the rest later for a more usable class }; #endif //WRAP_ITER_HPP__ From ff1db0c4af079ac94f97dc91cb15791b341e383b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 7 Nov 2013 15:04:23 -0500 Subject: [PATCH 0134/1866] Changes difference type to a template Argument --- slice.hpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/slice.hpp b/slice.hpp index 9131cbf0..0aa1e15c 100644 --- a/slice.hpp +++ b/slice.hpp @@ -8,18 +8,17 @@ #include namespace iter { - template - auto slice( - Container && container, - typename std::iterator_traits::difference_type begin, - typename std::iterator_traits::difference_type end, - typename std::iterator_traits::difference_type step = 1 + template + auto slice( Container && container, + DifferenceType begin, + DifferenceType end, + DifferenceType step = 1 ) -> iterator_range> { //it seems like you can handle negative and positive ranges the same //kept both checks to make checking for invalid slice more readable if (begin > end && step < 0) { - typename std::iterator_traits::difference_type new_end = end - ((end - begin) % step); + DifferenceType new_end = end - ((end - begin) % step); auto begin_iter = std::begin(container); std::advance(begin_iter,begin); auto end_iter = std::begin(container); @@ -29,7 +28,7 @@ namespace iter { make_wrap_iter(end_iter,step)); } else if (begin <= end && step > 0) { - typename std::iterator_traits::difference_type new_end = end - ((end - begin) % step); + DifferenceType new_end = end - ((end - begin) % step); auto begin_iter = std::begin(container); std::advance(begin_iter,begin); auto end_iter = std::begin(container); @@ -48,10 +47,10 @@ namespace iter { } //only give the end as an arg and assume step is 1 and begin is 0 - template + template auto slice( Container && container, - typename std::iterator_traits::difference_type end + DifferenceType end ) -> iterator_range> { return slice(std::forward(container),0,end); From c3c909e92728a870670ee4ad838434ec415cee73 Mon Sep 17 00:00:00 2001 From: Jared Schmitz Date: Thu, 7 Nov 2013 16:58:07 -0500 Subject: [PATCH 0135/1866] Refactor slice --- slice.hpp | 45 ++++++++++++++++----------------------------- 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/slice.hpp b/slice.hpp index 9ec4e59f..aea7d1ce 100644 --- a/slice.hpp +++ b/slice.hpp @@ -15,37 +15,24 @@ namespace iter { DifferenceType step = 1 ) -> iterator_range> { - //it seems like you can handle negative and positive ranges the same - //kept both checks to make checking for invalid slice more readable - if (begin > end && step < 0) { - DifferenceType new_end = end - ((end - begin) % step); - auto begin_iter = std::begin(container); - std::advance(begin_iter,begin); - auto end_iter = std::begin(container); - std::advance(end_iter,new_end); + // Check for an invalid slice. The sign of step must be equal to the + // sign of (end - begin). Since we don't force DifferenceType to be a + // primitive, just compare. + if (!(begin > end && step < 0) && !(begin <= end && step > 0)) { + // Just in case it gets dereferenced it will be the first element + // had the range been valid. This handles zero-length slices. + auto empty = std::next(std::begin(container), begin); return iterator_range>( - make_wrap_iter(begin_iter,step), - make_wrap_iter(end_iter,step)); - } - else if (begin <= end && step > 0) { - DifferenceType new_end = end - ((end - begin) % step); - auto begin_iter = std::begin(container); - std::advance(begin_iter,begin); - auto end_iter = std::begin(container); - std::advance(end_iter,new_end); - return iterator_range>( - make_wrap_iter(begin_iter,step), - make_wrap_iter(end_iter,step)); - } - else {//return an empty range for invalid slice - auto empty = std::begin(container); - std::advance(empty,begin); - //just in case it gets dereferenced it will be the first element had - //the range been valid - return iterator_range>( - make_wrap_iter(empty,step), - make_wrap_iter(empty,step)); + make_wrap_iter(empty, step), + make_wrap_iter(empty, step)); } + // Return the iterator range + DifferenceType new_end = end - ((end - begin) % step); + auto begin_iter = std::next(std::begin(container), begin); + auto end_iter = std::next(std::begin(container), new_end); + return iterator_range>( + make_wrap_iter(begin_iter,step), + make_wrap_iter(end_iter,step)); } //only give the end as an arg and assume step is 1 and begin is 0 From 39e19238dc896614550833388e4a5a804728a575 Mon Sep 17 00:00:00 2001 From: Jared Schmitz Date: Thu, 7 Nov 2013 17:07:41 -0500 Subject: [PATCH 0136/1866] Move specializations of iterator_traits into std --- chain.hpp | 8 +++++--- wrap_iter.hpp | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/chain.hpp b/chain.hpp index b360485a..36dfe7c0 100644 --- a/chain.hpp +++ b/chain.hpp @@ -93,9 +93,11 @@ namespace iter { iterator_range>(begin,end); } } +namespace std { template -struct std::iterator_traits> { - using difference_type = std::ptrdiff_t; - using iterator_category = std::input_iterator_tag; +struct iterator_traits> { + using difference_type = ptrdiff_t; + using iterator_category = input_iterator_tag; }; +} #endif //CHAIN_HPP diff --git a/wrap_iter.hpp b/wrap_iter.hpp index 1161a393..70017b4b 100644 --- a/wrap_iter.hpp +++ b/wrap_iter.hpp @@ -40,10 +40,12 @@ namespace iter { } } +namespace std { template - struct std::iterator_traits> { - using difference_type = typename std::iterator_traits::difference_type; - using iterator_category = typename std::iterator_traits::iterator_category; + struct iterator_traits> { + using difference_type = typename iterator_traits::difference_type; + using iterator_category = typename iterator_traits::iterator_category; //should add the rest later for a more usable class }; +} #endif //WRAP_ITER_HPP__ From 67a5967c7bb09e9318e1de721084be05ea750dfc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 7 Nov 2013 17:37:52 -0500 Subject: [PATCH 0137/1866] Updates compress to use IterBase --- compress.hpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/compress.hpp b/compress.hpp index 989c5983..11ba7c12 100644 --- a/compress.hpp +++ b/compress.hpp @@ -1,9 +1,10 @@ #ifndef COMPRESS__H__ #define COMPRESS__H__ -#include +#include + -// TODO everything in here +#include namespace iter { @@ -16,7 +17,7 @@ namespace iter { template - class Compressed { + class Compressed : public IterBase { private: Container & container; Selector & selectors; @@ -26,15 +27,12 @@ namespace iter { friend Compressed compress( Container &, Selector &); - // Type of the Container::Iterator, but since the name of that - // iterator can be anything, we have to grab it with this - using contained_iter_type = decltype(container.begin()); + using typename IterBase::contained_iter_type; - // The type returned when dereferencing the Container::Iterator - using contained_iter_ret = decltype(container.begin().operator*()); + using typename IterBase::contained_iter_ret; // Selector::Iterator type - using selector_iter_type = decltype(selectors.begin()); + using selector_iter_type = decltype(std::begin(selectors)); // Value constructor for use only in the compress function Compressed(Container & container, Selector & selectors) : From 3111fedd1d00698578535d78597cc54f82ffb731 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 7 Nov 2013 17:41:26 -0500 Subject: [PATCH 0138/1866] Replaces .begin/.end with std::begin/end --- compress.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compress.hpp b/compress.hpp index 11ba7c12..ff64bb9d 100644 --- a/compress.hpp +++ b/compress.hpp @@ -96,14 +96,14 @@ namespace iter { Iterator begin() const { return Iterator( - this->container.begin(), this->container.end(), - this->selectors.begin(), this->selectors.end()); + std::begin(this->container), std::end(this->container), + std::begin(this->selectors), std::end(this->selectors)); } Iterator end() const { return Iterator( - this->container.end(), this->container.end(), - this->selectors.end(), this->selectors.end()); + std::end(this->container), std::end(this->container), + std::end(this->selectors), std::end(this->selectors)); } }; From 0e4600e6c24558418267d2270309ae5a20c1ad06 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 7 Nov 2013 17:45:05 -0500 Subject: [PATCH 0139/1866] Updates to use Iterbase and std::begin/std::end --- dropwhile.hpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index cf730f0c..9ac899de 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -1,6 +1,8 @@ #ifndef DROPWHILE__H__ #define DROPWHILE__H__ +#include + #include namespace iter { @@ -13,7 +15,7 @@ namespace iter { DropWhile dropwhile(FilterFunc, Container &); template - class DropWhile { + class DropWhile : IterBase { private: Container & container; FilterFunc filter_func; @@ -21,12 +23,9 @@ namespace iter { friend DropWhile dropwhile( FilterFunc, Container &); - // Type of the Container::Iterator, but since the name of that - // iterator can be anything, we have to grab it with this - using contained_iter_type = decltype(container.begin()); + using typename IterBase::contained_iter_type; - // The type returned when dereferencing the Container::Iterator - using contained_iter_ret = decltype(container.begin().operator*()); + using typename IterBase::contained_iter_ret; // Value constructor for use only in the dropwhile function @@ -80,15 +79,15 @@ namespace iter { Iterator begin() const { return Iterator( - this->container.begin(), - this->container.end(), + std::begin(this->container), + std::end(this->container), this->filter_func); } Iterator end() const { return Iterator( - this->container.end(), - this->container.end(), + std::end(this->container), + std::end(this->container), this->filter_func); } From afe1511e7faec7421d60f3841f572163adb8c611 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 7 Nov 2013 17:47:02 -0500 Subject: [PATCH 0140/1866] Exposes iterbase type aliases publicly --- iterbase.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iterbase.hpp b/iterbase.hpp index 69cfe0c6..55936753 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -7,7 +7,7 @@ namespace iter { template class IterBase{ - protected: + public: // Type of the Container::Iterator, but since the name of that // iterator can be anything, we have to grab it with this using contained_iter_type = From cab3f5fd3e247d5d3aafb3fefc1042fda20f9a19 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 7 Nov 2013 17:48:53 -0500 Subject: [PATCH 0141/1866] Use iterbase type aliases --- filterfalse.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/filterfalse.hpp b/filterfalse.hpp index 34b16180..b18cca5c 100644 --- a/filterfalse.hpp +++ b/filterfalse.hpp @@ -1,7 +1,8 @@ #ifndef FILTER_FALSE__HPP__ #define FILTER_FALSE__HPP__ -#include "filter.hpp" +#include +#include namespace iter { @@ -15,7 +16,7 @@ namespace iter { FilterFunc filter_func; using contained_iter_ret = - decltype(std::declval().begin().operator*()); + typename IterBase::contained_iter_ret; public: PredicateFlipper(FilterFunc filter_func) : From b99b66e9f26eea47c43e74cd225840f7b82087d1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 7 Nov 2013 17:51:55 -0500 Subject: [PATCH 0142/1866] Updates to use IterBase and std::begin/end --- filter.hpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/filter.hpp b/filter.hpp index 0b201383..3ed8e7c4 100644 --- a/filter.hpp +++ b/filter.hpp @@ -1,6 +1,8 @@ #ifndef FILTER__H__ #define FILTER__H__ +#include + #include namespace iter { @@ -13,7 +15,7 @@ namespace iter { Filter filter(FilterFunc, Container &); template - class Filter { + class Filter : IterBase{ private: Container & container; FilterFunc filter_func; @@ -21,12 +23,10 @@ namespace iter { // The filter function is the only thing allowed to create a Filter friend Filter filter(FilterFunc, Container &); - // Type of the Container::Iterator, but since the name of that - // iterator can be anything, we have to grab it with this - using contained_iter_type = decltype(container.begin()); - // The type returned when dereferencing the Container::Iterator - using contained_iter_ret = decltype(container.begin().operator*()); + using typename IterBase::contained_iter_type; + + using typename IterBase::contained_iter_ret; // Value constructor for use only in the filter function Filter(FilterFunc filter_func, Container & container) : @@ -82,15 +82,15 @@ namespace iter { Iterator begin() const { return Iterator( - this->container.begin(), - this->container.end(), + std::begin(this->container), + std::end(this->container), this->filter_func); } Iterator end() const { return Iterator( - this->container.end(), - this->container.end(), + std::end(this->container), + std::end(this->container), this->filter_func); } @@ -114,7 +114,7 @@ namespace iter { class BoolTester { protected: using contained_iter_ret = - decltype(std::declval().begin().operator*()); + typename IterBase::contained_iter_ret; public: bool operator() (const contained_iter_ret item) const { From f8904b7a1f4bef21f92c849d5e83e60abb9d3921 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 7 Nov 2013 17:55:42 -0500 Subject: [PATCH 0143/1866] Updates to use IterBase and std::begin/end --- groupby.hpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index c468d83d..15d98eaf 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -1,8 +1,10 @@ #ifndef GROUP__BY__HPP #define GROUP__BY__HPP +#include #include +#include namespace iter { @@ -14,7 +16,7 @@ namespace iter { GroupBy groupby(Container &, KeyFunc); template - class GroupBy { + class GroupBy : IterBase { private: Container & container; KeyFunc key_func; @@ -22,12 +24,9 @@ namespace iter { // The filter function is the only thing allowed to create a Filter friend GroupBy groupby(Container &, KeyFunc); - // Type of the Container::Iterator, but since the name of that - // iterator can be anything, we have to grab it with this - using contained_iter_type = decltype(container.begin()); + using typename IterBase::contained_iter_type; - // The type returned when dereferencing the Container::Iterator - using contained_iter_ret = decltype(container.begin().operator*()); + using typename IterBase::contained_iter_ret; using key_func_ret = decltype(std::declval()( @@ -158,15 +157,15 @@ namespace iter { Iterator begin() const { return Iterator( - this->container.begin(), - this->container.end(), + std::begin(this->container), + std::end(this->container), this->key_func); } Iterator end() const { return Iterator( - this->container.end(), - this->container.end(), + std::end(this->container), + std::end(this->container), this->key_func); } @@ -182,7 +181,7 @@ namespace iter { class ItemReturner { private: using contained_iter_ret = - decltype(std::declval().begin().operator*()); + typename IterBase::contained_iter_ret; public: ItemReturner() = default; contained_iter_ret operator() (contained_iter_ret item) const { From 382bb63ecf513e0c1e82565726f784f9ba5a1f74 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 7 Nov 2013 17:58:49 -0500 Subject: [PATCH 0144/1866] Tweaks #includes --- cycle.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cycle.hpp b/cycle.hpp index 6a8eb713..a6aaa029 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -1,9 +1,10 @@ #ifndef CYCLE__H__ #define CYCLE__H__ -#include "iterbase.hpp" +#include #include +#include namespace iter { From 620237670855b2fd2ec2376e229c922da10f4cc1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 7 Nov 2013 17:58:53 -0500 Subject: [PATCH 0145/1866] Tweaks #includes --- dropwhile.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/dropwhile.hpp b/dropwhile.hpp index 9ac899de..ab9dccdf 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -4,6 +4,7 @@ #include #include +#include namespace iter { From f5089e52736359b749e056d757791b704818e0b7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 7 Nov 2013 17:58:57 -0500 Subject: [PATCH 0146/1866] Tweaks #includes --- enumerate.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/enumerate.hpp b/enumerate.hpp index 9bd871e9..620b8c7e 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -1,9 +1,10 @@ #ifndef ENUMERABLE__H__ #define ENUMERABLE__H__ -#include "iterbase.hpp" +#include #include +#include // enumerate functionality for python-style for-each enumerate loops From 6785425ca6775f67e321ab1ffd65bd9eac0d40c8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 7 Nov 2013 17:59:03 -0500 Subject: [PATCH 0147/1866] Tweaks #includes --- filter.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/filter.hpp b/filter.hpp index 3ed8e7c4..0af88a29 100644 --- a/filter.hpp +++ b/filter.hpp @@ -4,6 +4,7 @@ #include #include +#include namespace iter { From 70bdfa16eed3ef597261d7c6cc69398ae2c52a51 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Thu, 7 Nov 2013 18:02:31 -0500 Subject: [PATCH 0148/1866] added iterator_traits specializations to a bunch of iterators --- chain.hpp | 10 +++++----- combinations.hpp | 8 +++++++- combinations_with_replacement.hpp | 8 +++++++- grouper.hpp | 8 +++++++- moving_section.hpp | 8 +++++++- permutations.hpp | 8 +++++++- powerset.hpp | 8 +++++++- product.hpp | 9 ++++++++- zip.hpp | 7 +++++++ zip_longest.hpp | 10 +++++++++- 10 files changed, 71 insertions(+), 13 deletions(-) diff --git a/chain.hpp b/chain.hpp index 36dfe7c0..2c536a27 100644 --- a/chain.hpp +++ b/chain.hpp @@ -94,10 +94,10 @@ namespace iter { } } namespace std { -template -struct iterator_traits> { - using difference_type = ptrdiff_t; - using iterator_category = input_iterator_tag; -}; + template + struct iterator_traits> { + using difference_type = ptrdiff_t; + using iterator_category = input_iterator_tag; + }; } #endif //CHAIN_HPP diff --git a/combinations.hpp b/combinations.hpp index fab96317..8ef8939b 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -107,5 +107,11 @@ namespace iter { } }; } - +namespace std { + template + struct iterator_traits> { + using difference_type = ptrdiff_t; + using iterator_category = input_iterator_tag; + }; +} #endif //COMBINATIONS_HPP diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index 4196a491..043e0cf2 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -90,5 +90,11 @@ namespace iter { } }; } - +namespace std { + template + struct iterator_traits> { + using difference_type = ptrdiff_t; + using iterator_category = input_iterator_tag; + }; +} #endif //COMBINATIONS_WITH_REPLACEMENT_HPP diff --git a/grouper.hpp b/grouper.hpp index 5e57b2c8..b359ba7c 100644 --- a/grouper.hpp +++ b/grouper.hpp @@ -105,5 +105,11 @@ namespace iter { } }; } - +namespace std { + template + struct iterator_traits> { + using difference_type = ptrdiff_t; + using iterator_category = input_iterator_tag; + }; +} #endif // ifndef GROUPER_HPP diff --git a/moving_section.hpp b/moving_section.hpp index 36ce2906..d4dc52f4 100644 --- a/moving_section.hpp +++ b/moving_section.hpp @@ -67,5 +67,11 @@ namespace iter { } }; } - +namespace std { + template + struct iterator_traits> { + using difference_type = ptrdiff_t; + using iterator_category = input_iterator_tag; + }; +} #endif //MOVING_SECTION_HPP diff --git a/permutations.hpp b/permutations.hpp index cd94269c..839452c9 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -40,6 +40,12 @@ namespace iter { } }; } - +namespace std { + template + struct iterator_traits> { + using difference_type = ptrdiff_t; + using iterator_category = input_iterator_tag; + }; +} #endif //PERMUTATIONS_HPP diff --git a/powerset.hpp b/powerset.hpp index 7884f778..52398325 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -54,5 +54,11 @@ namespace iter { } }; } - +namespace std { + template + struct iterator_traits> { + using difference_type = ptrdiff_t; + using iterator_category = input_iterator_tag; + }; +} #endif //POWERSET_HPP diff --git a/product.hpp b/product.hpp index 676dad9a..6b47cfd2 100644 --- a/product.hpp +++ b/product.hpp @@ -2,6 +2,7 @@ #define PRODUCT_HPP #include #include +#include #include "iterator_range.hpp" namespace iter { @@ -108,7 +109,13 @@ namespace iter { //since != only checks the first one }; } - +namespace std { + template + struct iterator_traits> { + using difference_type = ptrdiff_t; + using iterator_category = input_iterator_tag; + }; +} #endif //PRODUCT_HPP diff --git a/zip.hpp b/zip.hpp index 0f1bff07..909e03f4 100644 --- a/zip.hpp +++ b/zip.hpp @@ -109,4 +109,11 @@ namespace iter { }; } +namespace std { + template + struct iterator_traits> { + using difference_type = ptrdiff_t; + using iterator_category = input_iterator_tag; + }; +} #endif //ZIP_HPP diff --git a/zip_longest.hpp b/zip_longest.hpp index 1ee30fff..56d67e90 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -95,5 +95,13 @@ namespace iter { } //should add reset after the end of a range is reached, just in case someone //tries to use it again -//this means it's only safe to use the range ONCE +//this means it's only safe to use the range ONCE, which is fine because of +//the input_iterator_tag +namespace std { + template + struct iterator_traits> { + using difference_type = ptrdiff_t; + using iterator_category = input_iterator_tag; + }; +} #endif //ZIP_LONGEST_HPP From 50685116e7e9bd9be627bfd963fe395d5fbd99e7 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Thu, 7 Nov 2013 18:20:48 -0500 Subject: [PATCH 0149/1866] updated itertools.hpp to include everything ' --- itertools.hpp | 57 ++++++++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/itertools.hpp b/itertools.hpp index e0214b96..4aecb577 100644 --- a/itertools.hpp +++ b/itertools.hpp @@ -1,34 +1,39 @@ #ifndef ITERTOOLS_HPP #define ITERTOOLS_HPP -#include "zip.hpp" -#include "reverse.hpp" -#include "slice.hpp" -#include "chain.hpp" -#include "combinations_with_replacement.hpp" -#include "combinations.hpp" -#include "compress.hpp" -#include "cycle.hpp" -#include "dropwhile.hpp" -#include "enumerate.hpp" -#include "filter.hpp" -#include "iterator_range.hpp" -#include "permutations.hpp" -#include "product.hpp" -#include "range.hpp" -#include "repeat.hpp" -#include "reverse.hpp" -#include "slice.hpp" -#include "takewhile.hpp" -#include "wrap_iter.hpp" -#include "zip.hpp" -#include "zip_longest.hpp" -#include "powerset.hpp" -#include "moving_section.hpp" -#include "grouper.hpp" - +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include //not sure if should include "iterator_range.hpp" //since it's already in everything #endif + From 882fd74606648ef8d3e912b87d8a61d4f7e4a084 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 7 Nov 2013 19:34:20 -0500 Subject: [PATCH 0150/1866] Tweaks includes --- imap.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imap.hpp b/imap.hpp index 5e156ff3..781679a9 100644 --- a/imap.hpp +++ b/imap.hpp @@ -1,7 +1,7 @@ #ifndef IMAP__H__ #define IMAP__H__ -#include "zip.hpp" +#include #include #include From 512196cc3897fe3ff2824666b8a599fb8dc3de74 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 7 Nov 2013 19:37:28 -0500 Subject: [PATCH 0151/1866] Updates to use IterBase and std::begin/end --- takewhile.hpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/takewhile.hpp b/takewhile.hpp index 11123561..a41c6109 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -1,7 +1,10 @@ #ifndef TAKEWHILE__H__ #define TAKEWHILE__H__ +#include + #include +#include namespace iter { @@ -13,7 +16,7 @@ namespace iter { TakeWhile takewhile(FilterFunc, Container &); template - class TakeWhile { + class TakeWhile : IterBase{ private: Container & container; FilterFunc filter_func; @@ -21,12 +24,9 @@ namespace iter { friend TakeWhile takewhile( FilterFunc, Container &); - // Type of the Container::Iterator, but since the name of that - // iterator can be anything, we have to grab it with this - using contained_iter_type = decltype(container.begin()); + using typename IterBase::contained_iter_type; - // The type returned when dereferencing the Container::Iterator - using contained_iter_ret = decltype(container.begin().operator*()); + using typename IterBase::contained_iter_ret; // Value constructor for use only in the takewhile function TakeWhile(FilterFunc filter_func, Container & container) : @@ -82,15 +82,15 @@ namespace iter { Iterator begin() const { return Iterator( - this->container.begin(), - this->container.end(), + std::begin(this->container), + std::end(this->container), this->filter_func); } Iterator end() const { return Iterator( - this->container.end(), - this->container.end(), + std::end(this->container), + std::end(this->container), this->filter_func); } From 78c3f3d59bf543171edc485e47a9e3a3502d18b4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 7 Nov 2013 19:42:09 -0500 Subject: [PATCH 0152/1866] Updates to use IterBase --- sorted.hpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/sorted.hpp b/sorted.hpp index b684ddfe..581b69c0 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -1,6 +1,9 @@ #ifndef SORTED__HPP__ #define SORTED__HPP__ +#include + +#include #include #include @@ -12,19 +15,18 @@ namespace iter { Sorted sorted(Container &, CompareFunc); template - class Sorted { + class Sorted : IterBase { private: friend Sorted sorted(Container &, CompareFunc); - using contained_iter_type = - decltype(std::declval().begin()); + using typename IterBase::contained_iter_type; + + using typename IterBase::contained_iter_ret; std::vector sorted_iters; - using sorted_iter_type = decltype(sorted_iters.begin()); - using contained_iter_ret = - decltype(sorted_iters.begin().operator*().operator*()); + using sorted_iter_type = decltype(std::begin(sorted_iters)); Sorted() = delete; Sorted & operator=(const Sorted &) = delete; From 9f0a16fa8c552ed9310274439c71cf277206dede Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 7 Nov 2013 19:50:46 -0500 Subject: [PATCH 0153/1866] Updates to use std::begin/end --- sorted.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sorted.hpp b/sorted.hpp index 581b69c0..b9b7a215 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -34,14 +34,14 @@ namespace iter { Sorted(Container & container, CompareFunc compare_func) { // Fill the sorted_iters vector with an iterator to each // element in the container - for (auto iter = container.begin(); - iter != container.end(); + for (auto iter = std::begin(container); + iter != std::end(container); ++iter) { sorted_iters.push_back(iter); } // sort by comparing the elements that the iterators point to - std::sort(sorted_iters.begin(), sorted_iters.end(), + std::sort(std::begin(sorted_iters), std::end(sorted_iters), [&] (const contained_iter_type & it1, const contained_iter_type & it2) { return compare_func(*it1, *it2); }); @@ -67,12 +67,12 @@ namespace iter { }; IteratorIterator begin() { - IteratorIterator iteriter(sorted_iters.begin()); + IteratorIterator iteriter(std::begin(sorted_iters)); return iteriter; } IteratorIterator end() { - IteratorIterator iteriter(sorted_iters.end()); + IteratorIterator iteriter(std::end(sorted_iters)); return iteriter; } }; @@ -88,13 +88,13 @@ namespace iter { decltype(sorted( container, std::less().begin().operator*())>() + *std::begin(std::declval()))>() )) { return sorted( container, std::less().begin().operator*())>() + *std::begin(std::declval()))>() ); } From ca782827d90ddbf865a60ac00f2f92bff3fbfd72 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 7 Nov 2013 19:55:16 -0500 Subject: [PATCH 0154/1866] Sorts by first character to avoid confusion --- tests/testsorted.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/testsorted.cpp b/tests/testsorted.cpp index 7abdafc6..2a0bea29 100644 --- a/tests/testsorted.cpp +++ b/tests/testsorted.cpp @@ -18,11 +18,12 @@ int main() 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[1] < s2[1]; })) { + return s1[0] < s2[0]; })) { std::cout << s << '\n'; } From 3339646d49503cfff70c4242f651aabb34ded2c5 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Fri, 8 Nov 2013 18:19:58 -0500 Subject: [PATCH 0155/1866] grouper readme written --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index f6646077..7cf6e800 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ library. [reverse](#reverse)
[slice](#slice)
[moving_section](#moving_section)
+[grouper](#grouper)
##### Combinatoric fuctions [product](#product)
@@ -328,6 +329,26 @@ for (auto sec : moving_section(v,4)) { std::cout << std::endl; } ``` +grouper +------ + +grouper is very similar to moving section, exception instead of the +section sliding by only 1 it goes the length of the full section. + +Example usage: +```c++ +std::vector v {1,2,3,4,5,6,7,8,9}; +for (auto sec : grouper(v,4)) +//each section will have 4 elements +//except the last one may be cut short +{ + for (auto i : sec) { + std::cout << i << " "; + i.get() *= 2; + } + std::cout << std::endl; +} +``` product ------ From 47b853a016a6b8f23f56142ed868ebbecbc51081 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Fri, 8 Nov 2013 18:28:57 -0500 Subject: [PATCH 0156/1866] Updated for filter adaptors --- README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/README.md b/README.md index 7cf6e800..b227a8a4 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ library. [imap](#imap)
[filter](#filter)
[filterfalse](#filterfalse)
+[unique_everseen](#unique_everseen)
+[unique_justseen](#unique_justseen)
[takewhile](#takewhile)
[dropwhile](#dropwhile)
[cycle](#cycle)
@@ -134,6 +136,33 @@ for(auto i : filterfalse(vec)) { cout << i << '\n'; } ``` +unique_everseen +--------------- +This is a filter adaptor that only generates values that have never been seen +before. For this algo to work your object must be specialized for `std::hash` +otherwise it will not be very efficient + +Example Usage: +```c++ +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; +``` + +unique_justseen +-------------- +Another filter adaptor that only prevents duplicates that are in a row, if the +sequence is sorted it will work exactly the same as `unique_justseen`, in that +case it will be better and more efficient to use. + +Example Usage: +```c++ +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 << std::endl; +``` takewhile --------- From f8b9e620187f468b96b6a2f5e0badb1e7a0f6386 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Sat, 9 Nov 2013 12:46:20 -0500 Subject: [PATCH 0157/1866] fixed small error in unique_everseen test file --- tests/testunique_everseen.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/testunique_everseen.cpp b/tests/testunique_everseen.cpp index e373a8a3..d57674e7 100644 --- a/tests/testunique_everseen.cpp +++ b/tests/testunique_everseen.cpp @@ -14,7 +14,6 @@ int main() { }std::cout << std::endl; } { - //should work same as justseen here 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 << " "; From 5ba041c54f920aafcc9eee0870b28e1b420b4e31 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Sat, 9 Nov 2013 14:45:28 -0500 Subject: [PATCH 0158/1866] Added zip test file for boost --- boost_tests/.gitignore | 3 + boost_tests/SConstruct | 31 +++++++ boost_tests/pattern_files/zip_output.txt | 36 ++++++++ boost_tests/testzip.cpp | 100 +++++++++++++++++++++++ 4 files changed, 170 insertions(+) create mode 100644 boost_tests/.gitignore create mode 100644 boost_tests/SConstruct create mode 100644 boost_tests/pattern_files/zip_output.txt create mode 100644 boost_tests/testzip.cpp diff --git a/boost_tests/.gitignore b/boost_tests/.gitignore new file mode 100644 index 00000000..5d88f468 --- /dev/null +++ b/boost_tests/.gitignore @@ -0,0 +1,3 @@ +*.o +*.dblite +testzip diff --git a/boost_tests/SConstruct b/boost_tests/SConstruct new file mode 100644 index 00000000..13eb390c --- /dev/null +++ b/boost_tests/SConstruct @@ -0,0 +1,31 @@ +import platform +import os + +env = Environment( + CXX='c++', + CXXFLAGS= ['-g', '-Wall', '-Wextra', '-Weffc++', '-Wno-unused-parameter' , + '-pedantic', '-std=c++11', + '-I/usr/local/include', '-I/opt/local/include'], + CPPPATH='..', + LINKFLAGS=['-L/usr/local/lib', '-L/opt/local/lib'] + ) + +# allows highighting to print to terminal from compiler output +env['ENV']['TERM'] = os.environ['TERM'] + +# if on MAC, needs the linker flag for -stdlib=libc++ +# obselete with mavericks +""" if platform.system() == 'Darwin': + env['CXX'] += '-stdlib=libc++' + env['CXXFLAGS'].append('-stdlib=libc++') +""" + + + +progs = Split( ''' + zip + ''') + + +for p in progs: + env.Program('test{0}.cpp'.format(p)) diff --git a/boost_tests/pattern_files/zip_output.txt b/boost_tests/pattern_files/zip_output.txt new file mode 100644 index 00000000..f2ea8edd --- /dev/null +++ b/boost_tests/pattern_files/zip_output.txt @@ -0,0 +1,36 @@ +1 +hello +4 +good day +9 +goodbye +69 +hello +69 +good day +69 +goodbye + +Variadic template zip iterator +1 1.2 i 1.2 +2 1.4 like 1.2 +3 12.3 apples 1.2 +4 4.5 alot 1.2 + +1 i 2.2 1.2 +2 like 2.2 1.2 +3 apples 2.2 1.2 +4 alot 2.2 1.2 + +Try some weird range differences + + +2.2 i 1 1.2 +2.2 like 2 1.2 +2.2 apples 3 1.2 +2.2 alot 4 1.2 + +1 asdfas 1.1 +5 aaron 2.2 +1 ryan 3.3 +2 apple 4.4 diff --git a/boost_tests/testzip.cpp b/boost_tests/testzip.cpp new file mode 100644 index 00000000..cf2ced29 --- /dev/null +++ b/boost_tests/testzip.cpp @@ -0,0 +1,100 @@ +#include "../zip.hpp" +#include "../chain.hpp" +#include +#include +#include +#include + +#define BOOST_TEST_MODULE ZipTest test +#include +#include +using boost::test_tools::output_test_stream; + + +using iter::zip; + +BOOST_AUTO_TEST_CASE ( zip_test ) { + + output_test_stream output("pattern_files/zip_output.txt",true); + //Ryan's test + { + std::vector ivec{1, 4, 9, 16, 25, 36}; + std::vector svec{"hello", "good day", "goodbye"}; + + for (auto e : zip(ivec, svec)) { + auto &i = std::get<0>(e); + output << i << std::endl; + i = 69; + output << std::get<1>(e) << std::endl; + } + BOOST_REQUIRE(output.match_pattern()); + for (auto e : zip(ivec, svec)) { + output << std::get<0>(e) << std::endl; + output << std::get<1>(e) << std::endl; + } + BOOST_REQUIRE(output.match_pattern()); + } + //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}}; + output << std::endl << "Variadic template zip iterator" << std::endl; + for (auto e : iter::zip(i,f,s,d)) { + output << 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 + } + output<(e) << " " + << std::get<1>(e) << " " + << std::get<2>(e) << " " + << std::get<3>(e) << std::endl; + } + BOOST_REQUIRE(output.match_pattern()); + output << std::endl << "Try some weird range differences" << std::endl; + std::vector empty{}; + for (auto e : iter::zip(empty,f,s,d)) { + output << std::get<0>(e) << " " + << std::get<1>(e) << " " + << std::get<2>(e) << " " + << std::get<3>(e) << std::endl; + } + output<(e) << " " + << std::get<1>(e) << " " + << std::get<2>(e) << " " + << std::get<3>(e) << std::endl; + }//both should print nothing + output<(e) << " " + << std::get<1>(e) << " " + << std::get<2>(e) << " " + << std::get<3>(e) << std::endl; + } + output< constvector{1.1,2.2,3.3,4.4}; + for (auto e : zip(iter::chain(std::vector{1,5},std::array{{1,2}}), + std::initializer_list{"asdfas","aaron","ryan","apple","juice"}, + constvector)) + { + + output << std::get<0>(e) << " " + << std::get<1>(e) << " " + << std::get<2>(e) << std::endl; + } + BOOST_REQUIRE(output.match_pattern()); + } + BOOST_REQUIRE(output.match_pattern()); +} + From f6525c15ae163f2b505cf18eea63329d7b1d8092 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 13 Nov 2013 11:23:10 -0500 Subject: [PATCH 0159/1866] Adds support for initializer_lists to enumerate --- enumerate.hpp | 20 ++++++++++++++------ tests/testenumerate.cpp | 5 +++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 620b8c7e..0bee2657 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -5,6 +5,7 @@ #include #include +#include // enumerate functionality for python-style for-each enumerate loops @@ -22,9 +23,11 @@ namespace iter { template class Enumerable; - template - Enumerable enumerate(Container &); + template + Enumerable> enumerate(std::initializer_list && il); + template + Enumerable enumerate(Container &&); template class Enumerable : public IterBase{ @@ -32,19 +35,19 @@ namespace iter { Container & container; // The only thing allowed to directly instantiate an Enumerable is // the enumerate function - friend Enumerable enumerate(Container &); + //friend Enumerable enumerate(Container &); using typename IterBase::contained_iter_type; using typename IterBase::contained_iter_ret; + public: // Value constructor for use only in the enumerate function Enumerable(Container & container) : container(container) { } Enumerable () = delete; Enumerable & operator=(const Enumerable &) = delete; - public: Enumerable(const Enumerable &) = default; // "yielded" by the Enumerable::Iterator. Has a .index, and a @@ -98,10 +101,15 @@ namespace iter { // Helper function to instantiate an Enumerable template - Enumerable enumerate(Container & container) { - return Enumerable(container); + Enumerable enumerate(Container && container) { + return Enumerable(std::forward(container)); } + template + Enumerable> enumerate(std::initializer_list && il) + { + return Enumerable>(il); + } } diff --git a/tests/testenumerate.cpp b/tests/testenumerate.cpp index faebd71f..a6b3adf9 100644 --- a/tests/testenumerate.cpp +++ b/tests/testenumerate.cpp @@ -31,5 +31,10 @@ int main() { std::cout << e.index << ": " << e.element << '\n'; } + + for (auto e : enumerate({0, 1, 4, 9, 16, 25})) { + std::cout << e.index << "^2 = " << e.element << '\n'; + } + return 0; } From 2a4f4c18b49b3c6e5ca7df2fbe4088d7149b145e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 13 Nov 2013 23:04:59 -0500 Subject: [PATCH 0160/1866] Makes Enumerable ctor private again --- enumerate.hpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 0bee2657..816bd6e6 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -24,7 +24,8 @@ namespace iter { class Enumerable; template - Enumerable> enumerate(std::initializer_list && il); + Enumerable> enumerate( + std::initializer_list &&); template Enumerable enumerate(Container &&); @@ -33,18 +34,21 @@ namespace iter { class Enumerable : public IterBase{ private: Container & container; + // The only thing allowed to directly instantiate an Enumerable is // the enumerate function - //friend Enumerable enumerate(Container &); + friend Enumerable enumerate(Container &&); + template + friend Enumerable> enumerate(std::initializer_list &&); using typename IterBase::contained_iter_type; using typename IterBase::contained_iter_ret; + Enumerable(Container & container) : container(container) { } public: // Value constructor for use only in the enumerate function - Enumerable(Container & container) : container(container) { } Enumerable () = delete; Enumerable & operator=(const Enumerable &) = delete; From d6e3ee29a21bf6dc9dfabba41f608d4b7243c850 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 13 Nov 2013 23:33:21 -0500 Subject: [PATCH 0161/1866] Starts converting slice.hpp to use helper Slice --- slice.hpp | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/slice.hpp b/slice.hpp index aea7d1ce..c989de7a 100644 --- a/slice.hpp +++ b/slice.hpp @@ -45,6 +45,87 @@ namespace iter { return slice(std::forward(container),0,end); } + //Forward declarations of Slice and slice + template + class Slice; + + //template + //Slice> slice( std::initializer_list &&); + + template + Slice slice(Container &&); + + template + class Slice : public IterBase{ + private: + Container & container; + + // The only thing allowed to directly instantiate an Slice is + // the slice function + friend Slice slice(Container &&); + //template + //friend Slice> slice(std::initializer_list &&); + + using typename IterBase::contained_iter_type; + + using typename IterBase::contained_iter_ret; + + Slice(Container & container) : container(container) { } + + public: + // Value constructor for use only in the slice function + Slice () = delete; + Slice & operator=(const Slice &) = delete; + + Slice(const Slice &) = default; + + + // Holds an iterator of the contained type and a size_t for the + // index. Each call to ++ increments both of these data members. + // Each dereference returns an IterYield. + class Iterator { + private: + contained_iter_type sub_iter; + public: + Iterator (contained_iter_type si) : + sub_iter(si) + { } + + IterYield operator*() const { + return IterYield(this->index, *this->sub_iter); + } + + Iterator & operator++() { + ++this->sub_iter; + return *this; + } + + bool operator!=(const Iterator & other) const { + return this->sub_iter != other.sub_iter; + } + }; + + Iterator begin() const { + return Iterator(std::begin(this->container)); + } + + Iterator end() const { + return Iterator(std::end(this->container)); + } + + }; + // Helper function to instantiate an Slice + template + Slice slice(Container && container) { + return Slice(std::forward(container)); + } + + template + Slice> slice(std::initializer_list && il) + { + return Slice>(il); + } + } #endif //SLICE_HPP From d5614a1ae270d5d691ae1c9a89bce2a54746a515 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 13 Nov 2013 23:37:43 -0500 Subject: [PATCH 0162/1866] Adds test with step larger than range for slice Should give a slice with only the first element, instead gives an empty slice --- tests/testslice.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/testslice.cpp b/tests/testslice.cpp index 84159637..030beb66 100644 --- a/tests/testslice.cpp +++ b/tests/testslice.cpp @@ -8,6 +8,13 @@ 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; } From 7a3584c39be5a2cb8843f8e2241ff18a4a7bd45f Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Wed, 13 Nov 2013 23:50:57 -0500 Subject: [PATCH 0163/1866] changed testzip --- boost_tests/testzip.cpp | 8 +++++++- tests/testzip.cpp | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/boost_tests/testzip.cpp b/boost_tests/testzip.cpp index cf2ced29..802924d3 100644 --- a/boost_tests/testzip.cpp +++ b/boost_tests/testzip.cpp @@ -6,7 +6,13 @@ #include #define BOOST_TEST_MODULE ZipTest test -#include + +#ifdef COMPILED_BINARY + #include +#else + #include +#endif + #include using boost::test_tools::output_test_stream; diff --git a/tests/testzip.cpp b/tests/testzip.cpp index ea30599a..eb0ef476 100644 --- a/tests/testzip.cpp +++ b/tests/testzip.cpp @@ -71,7 +71,7 @@ int main() { } std::cout< constvector{1.1,2.2,3.3,4.4}; - for (auto e : zip(iter::chain(std::vector{1,5},std::array{{1,2}}), + for (auto e : zip(iter::chain(std::vector(5,5),std::array{{1,2}}), std::initializer_list{"asdfas","aaron","ryan","apple","juice"}, constvector)) { From 4f76b9984456de6c22c546b4bc0bde811190bc1e Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Wed, 13 Nov 2013 23:53:24 -0500 Subject: [PATCH 0164/1866] added include in enumerate --- enumerate.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/enumerate.hpp b/enumerate.hpp index 816bd6e6..ef367d52 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -6,6 +6,7 @@ #include #include #include +#include // enumerate functionality for python-style for-each enumerate loops From 1dd3bbf152be95e74925a524ecd58a3d8a9049a3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 13 Nov 2013 23:57:26 -0500 Subject: [PATCH 0165/1866] continuing development on slice... --- slice.hpp | 92 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 47 insertions(+), 45 deletions(-) diff --git a/slice.hpp b/slice.hpp index c989de7a..7cfd5674 100644 --- a/slice.hpp +++ b/slice.hpp @@ -8,61 +8,25 @@ #include namespace iter { - template - auto slice( Container && container, - DifferenceType begin, - DifferenceType end, - DifferenceType step = 1 - ) -> iterator_range> - { - // Check for an invalid slice. The sign of step must be equal to the - // sign of (end - begin). Since we don't force DifferenceType to be a - // primitive, just compare. - if (!(begin > end && step < 0) && !(begin <= end && step > 0)) { - // Just in case it gets dereferenced it will be the first element - // had the range been valid. This handles zero-length slices. - auto empty = std::next(std::begin(container), begin); - return iterator_range>( - make_wrap_iter(empty, step), - make_wrap_iter(empty, step)); - } - // Return the iterator range - DifferenceType new_end = end - ((end - begin) % step); - auto begin_iter = std::next(std::begin(container), begin); - auto end_iter = std::next(std::begin(container), new_end); - return iterator_range>( - make_wrap_iter(begin_iter,step), - make_wrap_iter(end_iter,step)); - - } - //only give the end as an arg and assume step is 1 and begin is 0 - template - auto slice( - Container && container, - DifferenceType end - ) -> iterator_range> - { - return slice(std::forward(container),0,end); - } //Forward declarations of Slice and slice - template - class Slice; + //template + //class Slice; //template //Slice> slice( std::initializer_list &&); - template - Slice slice(Container &&); + //template + //Slice slice(Container &&); - template + template class Slice : public IterBase{ private: Container & container; // The only thing allowed to directly instantiate an Slice is // the slice function - friend Slice slice(Container &&); + //friend Slice slice(Container &&); //template //friend Slice> slice(std::initializer_list &&); @@ -70,9 +34,16 @@ namespace iter { using typename IterBase::contained_iter_ret; - Slice(Container & container) : container(container) { } public: + Slice(Container & container, DifferenceType start, + DifferenceType stop, DifferenceType step=1) : + container(container), + start(start), + stop(stop), + step(step) + { } + // Value constructor for use only in the slice function Slice () = delete; Slice & operator=(const Slice &) = delete; @@ -115,17 +86,48 @@ namespace iter { }; // Helper function to instantiate an Slice - template - Slice slice(Container && container) { + template + Slice slice(Container && container) { return Slice(std::forward(container)); } +#if 0 template Slice> slice(std::initializer_list && il) { return Slice>(il); } +#endif + // Check for an invalid slice. The sign of step must be equal to the + // sign of (end - begin). Since we don't force DifferenceType to be a + // primitive, just compare. + if (!(begin > end && step < 0) && !(begin <= end && step > 0)) { + // Just in case it gets dereferenced it will be the first element + // had the range been valid. This handles zero-length slices. + auto empty = std::next(std::begin(container), begin); + return iterator_range>( + make_wrap_iter(empty, step), + make_wrap_iter(empty, step)); + } + // Return the iterator range + DifferenceType new_end = end - ((end - begin) % step); + auto begin_iter = std::next(std::begin(container), begin); + auto end_iter = std::next(std::begin(container), new_end); + return iterator_range>( + make_wrap_iter(begin_iter,step), + make_wrap_iter(end_iter,step)); + + } + //only give the end as an arg and assume step is 1 and begin is 0 + template + auto slice( + Container && container, + DifferenceType end + ) -> iterator_range> + { + return slice(std::forward(container),0,end); + } } #endif //SLICE_HPP From 25d753517ed4047c3cf43a3e9bd939ca75e7766c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 14 Nov 2013 00:15:36 -0500 Subject: [PATCH 0166/1866] Rough completion of slice conversion --- slice.hpp | 74 +++++++++++++++++++++---------------------------------- 1 file changed, 28 insertions(+), 46 deletions(-) diff --git a/slice.hpp b/slice.hpp index 7cfd5674..fffc71ca 100644 --- a/slice.hpp +++ b/slice.hpp @@ -1,8 +1,7 @@ #ifndef SLICE_HPP #define SLICE_HPP -#include "iterator_range.hpp" -#include "wrap_iter.hpp" +#include #include #include @@ -19,10 +18,13 @@ namespace iter { //template //Slice slice(Container &&); - template + template class Slice : public IterBase{ private: Container & container; + DifferenceType start; + DifferenceType stop; + DifferenceType step; // The only thing allowed to directly instantiate an Slice is // the slice function @@ -37,12 +39,17 @@ namespace iter { public: Slice(Container & container, DifferenceType start, - DifferenceType stop, DifferenceType step=1) : + DifferenceType stop, DifferenceType step) : container(container), start(start), stop(stop), step(step) - { } + { + if ((start < stop && step) <=0 || + (start > stop && step >=0)){ + this->stop = start; + } + } // Value constructor for use only in the slice function Slice () = delete; @@ -62,8 +69,8 @@ namespace iter { sub_iter(si) { } - IterYield operator*() const { - return IterYield(this->index, *this->sub_iter); + contained_iter_ret operator*() const { + return *this->sub_iter; } Iterator & operator++() { @@ -77,56 +84,31 @@ namespace iter { }; Iterator begin() const { - return Iterator(std::begin(this->container)); + return Iterator(std::next( + std::begin(this->container), this->start)); } Iterator end() const { - return Iterator(std::end(this->container)); + return Iterator(std::next( + std::begin(this->container), this->stop)); } }; // Helper function to instantiate an Slice - template - Slice slice(Container && container) { - return Slice(std::forward(container)); - } - -#if 0 - template - Slice> slice(std::initializer_list && il) - { - return Slice>(il); + template + Slice slice( + Container && container, DifferenceType start, + DifferenceType stop, DifferenceType step=1) { + return Slice( + std::forward(container), start, stop, step); } -#endif - - // Check for an invalid slice. The sign of step must be equal to the - // sign of (end - begin). Since we don't force DifferenceType to be a - // primitive, just compare. - if (!(begin > end && step < 0) && !(begin <= end && step > 0)) { - // Just in case it gets dereferenced it will be the first element - // had the range been valid. This handles zero-length slices. - auto empty = std::next(std::begin(container), begin); - return iterator_range>( - make_wrap_iter(empty, step), - make_wrap_iter(empty, step)); - } - // Return the iterator range - DifferenceType new_end = end - ((end - begin) % step); - auto begin_iter = std::next(std::begin(container), begin); - auto end_iter = std::next(std::begin(container), new_end); - return iterator_range>( - make_wrap_iter(begin_iter,step), - make_wrap_iter(end_iter,step)); - } //only give the end as an arg and assume step is 1 and begin is 0 template - auto slice( - Container && container, - DifferenceType end - ) -> iterator_range> - { - return slice(std::forward(container),0,end); + Slice slice( + Container && container, DifferenceType stop) { + return Slice( + std::forward(container), 0, stop, 1); } } From d6304d76aa3c1118ba05964e9ec6f9e12e007a9a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 14 Nov 2013 00:29:35 -0500 Subject: [PATCH 0167/1866] Almost functioning conversion of slice --- slice.hpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/slice.hpp b/slice.hpp index fffc71ca..af93db28 100644 --- a/slice.hpp +++ b/slice.hpp @@ -4,7 +4,6 @@ #include #include -#include namespace iter { @@ -45,7 +44,7 @@ namespace iter { stop(stop), step(step) { - if ((start < stop && step) <=0 || + if ((start < stop && step <=0) || (start > stop && step >=0)){ this->stop = start; } @@ -64,9 +63,11 @@ namespace iter { class Iterator { private: contained_iter_type sub_iter; + DifferenceType step; public: - Iterator (contained_iter_type si) : - sub_iter(si) + Iterator (contained_iter_type si, DifferenceType step) : + sub_iter(si), + step(step) { } contained_iter_ret operator*() const { @@ -74,7 +75,7 @@ namespace iter { } Iterator & operator++() { - ++this->sub_iter; + std::advance(this->sub_iter, this->step); return *this; } @@ -84,13 +85,15 @@ namespace iter { }; Iterator begin() const { - return Iterator(std::next( - std::begin(this->container), this->start)); + return Iterator( + std::next(std::begin(this->container), this->start), + this->step); } Iterator end() const { - return Iterator(std::next( - std::begin(this->container), this->stop)); + return Iterator( + std::next(std::begin(this->container), this->stop), + this->step); } }; From 75cdb3ca251693c1c3e9b5f92a1f2ffa5640e188 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 14 Nov 2013 00:32:48 -0500 Subject: [PATCH 0168/1866] Adds description messages --- tests/testslice.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/testslice.cpp b/tests/testslice.cpp index 84159637..178bbac7 100644 --- a/tests/testslice.cpp +++ b/tests/testslice.cpp @@ -24,11 +24,13 @@ int main() { for (auto i : iter::slice(a,0,15,3)) { std::cout << i << std::endl; } - std::cout< Date: Thu, 14 Nov 2013 00:46:27 -0500 Subject: [PATCH 0169/1866] Removes -Weffc++ from compilation flags --- tests/SConstruct | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/SConstruct b/tests/SConstruct index 8c300998..ceb1f196 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -2,8 +2,8 @@ import platform import os env = Environment( - CXX='c++', - CXXFLAGS= ['-g', '-Wall', '-Wextra', '-Weffc++', + CXX='clang++', + CXXFLAGS= ['-g', '-Wall', '-Wextra', '-pedantic', '-std=c++11', '-I/usr/local/include'], CPPPATH='..', From b18ff9164339441196dff649c8b1e375491d8e34 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 14 Nov 2013 00:48:38 -0500 Subject: [PATCH 0170/1866] Fixes a bunch of comments --- slice.hpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/slice.hpp b/slice.hpp index af93db28..f8995214 100644 --- a/slice.hpp +++ b/slice.hpp @@ -44,22 +44,19 @@ namespace iter { stop(stop), step(step) { + // sets stop = start if the range is empty if ((start < stop && step <=0) || (start > stop && step >=0)){ this->stop = start; } } - // Value constructor for use only in the slice function Slice () = delete; Slice & operator=(const Slice &) = delete; Slice(const Slice &) = default; - // Holds an iterator of the contained type and a size_t for the - // index. Each call to ++ increments both of these data members. - // Each dereference returns an IterYield. class Iterator { private: contained_iter_type sub_iter; @@ -97,7 +94,8 @@ namespace iter { } }; - // Helper function to instantiate an Slice + + // Helper function to instantiate a Slice template Slice slice( Container && container, DifferenceType start, From 0630c71fae866f27e705390e97b79f9ec9eea615 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 14 Nov 2013 01:11:28 -0500 Subject: [PATCH 0171/1866] adds test with imperfect step size --- tests/testslice.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/testslice.cpp b/tests/testslice.cpp index 178bbac7..690a1cd9 100644 --- a/tests/testslice.cpp +++ b/tests/testslice.cpp @@ -30,6 +30,11 @@ int main() { std::cout << i << std::endl; } + std::cout<< "\nunevent step [0:5:3]\n"; + for (auto i : iter::slice(a, 0, 5, 3)) { + std::cout << i << '\n'; + } + std::cout<< "\nInvalid range [1:10:-1]\n"; for (auto i : iter::slice(a,1,10,-1)) { //invalid range returns two begin iters From ac6a076158a4012b2ea0bd204a14a6db813fa603 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 14 Nov 2013 01:11:50 -0500 Subject: [PATCH 0172/1866] Handles case of uneven step size with a slice like [0:5:3] the position isn't exactly equal to the end, so the Slice::Iterator::operator!= has to handle that case --- slice.hpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/slice.hpp b/slice.hpp index f8995214..1e44e4e7 100644 --- a/slice.hpp +++ b/slice.hpp @@ -60,10 +60,16 @@ namespace iter { class Iterator { private: contained_iter_type sub_iter; - DifferenceType step; + DifferenceType current; + const DifferenceType stop; + const DifferenceType step; + public: - Iterator (contained_iter_type si, DifferenceType step) : + Iterator (contained_iter_type si, DifferenceType start, + DifferenceType stop, DifferenceType step) : sub_iter(si), + current(start), + stop(stop), step(step) { } @@ -73,24 +79,26 @@ namespace iter { Iterator & operator++() { std::advance(this->sub_iter, this->step); + this->current += this->step; return *this; } - bool operator!=(const Iterator & other) const { - return this->sub_iter != other.sub_iter; + bool operator!=(const Iterator &) const { + return (this->step > 0 && this->current < this->stop)|| + (this->step < 0 && this->current > this->stop); } }; Iterator begin() const { return Iterator( std::next(std::begin(this->container), this->start), - this->step); + this->start, this->stop, this->step); } Iterator end() const { return Iterator( std::next(std::begin(this->container), this->stop), - this->step); + this->stop, this->stop, this->step); } }; From 0ed6f67121417474d463d3fa1acbd586dd025c01 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Thu, 14 Nov 2013 02:05:07 -0500 Subject: [PATCH 0173/1866] Fixed slice but not the pythonic way --- slice.hpp | 6 ++++++ tests/testslice.cpp | 11 +++++++++++ 2 files changed, 17 insertions(+) diff --git a/slice.hpp b/slice.hpp index 1e44e4e7..60877039 100644 --- a/slice.hpp +++ b/slice.hpp @@ -49,6 +49,12 @@ namespace iter { (start > stop && step >=0)){ this->stop = start; } + if (this->stop > static_cast(container.size())) { + this->stop = static_cast(container.size()); + } + if (this->start < static_cast(container.size())) { + this->start = 0; + } } Slice () = delete; diff --git a/tests/testslice.cpp b/tests/testslice.cpp index 98f3806f..6db6da85 100644 --- a/tests/testslice.cpp +++ b/tests/testslice.cpp @@ -47,4 +47,15 @@ int main() { //invalid range returns two begin iters std::cout << i << std::endl; } + std::cout<< "\nOversize range [1:100:1]\n"; + for (auto i : iter::slice(a,1,100,1)) { + //invalid range returns two begin iters + std::cout << i << std::endl; + } + std::cout<< "\nOversize range and undersize[1:100:1]\n"; + for (auto i : iter::slice(a,-100,100,1)) { + //invalid range returns two begin iters + std::cout << i << std::endl; + } + } From 1b35cef27f6c31651f09b325660e5580d16a437f Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Thu, 14 Nov 2013 02:07:40 -0500 Subject: [PATCH 0174/1866] small error --- slice.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slice.hpp b/slice.hpp index 60877039..7e9759c6 100644 --- a/slice.hpp +++ b/slice.hpp @@ -52,7 +52,7 @@ namespace iter { if (this->stop > static_cast(container.size())) { this->stop = static_cast(container.size()); } - if (this->start < static_cast(container.size())) { + if (this->start < 0) { this->start = 0; } } From 092f51c6aa5bd743248e25b84675f95d328aea55 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 14 Nov 2013 13:57:54 -0500 Subject: [PATCH 0175/1866] Handle skipping whole or part of group Each group has a "completed" mutable bool that determines whether it has been exhausted or not. The Group destructor checks the flag and if it is false, it exhausts the group. --- groupby.hpp | 45 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index 15d98eaf..0a3a67d2 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -6,7 +6,6 @@ #include #include - namespace iter { template @@ -103,35 +102,63 @@ namespace iter { class Group { private: friend Iterator; + friend class GroupIterator; Iterator *owner; key_func_ret key; + mutable bool completed = false; Group(Iterator *owner, key_func_ret key) : owner(owner), key(key) { } + public: + ~Group() { + if (!this->completed) { + for (auto iter = this->begin(), end = this->end(); + iter != end; + ++iter) { } + } + } + + Group () = delete; - public: - Group (const Group &) = default; + Group (const Group &other) : + owner(other.owner), + key(other.key), + completed(other.completed) { + other.completed = true; + } class GroupIterator { private: Iterator * owner; const key_func_ret key; + const Group * group; + + bool not_at_end() const { + return !this->owner->exhausted() && + this->owner->next_key() == this->key; + } public: - GroupIterator(Iterator * owner, key_func_ret key) : + GroupIterator(Iterator * owner, const Group *group, + key_func_ret key) : owner(owner), - key(key) + key(key), + group(group) { } GroupIterator(const GroupIterator &) = default; bool operator!=(const GroupIterator &) const { - return !this->owner->exhausted() && - this->owner->next_key() == this->key; + if (this->not_at_end()) { + return true; + } else { + this->group->completed = true; + return false; + } } GroupIterator & operator++() { @@ -145,11 +172,11 @@ namespace iter { }; GroupIterator begin() const { - return GroupIterator(this->owner, key); + return GroupIterator(this->owner, this, key); } GroupIterator end() const { - return GroupIterator(this->owner, key); + return GroupIterator(this->owner, this, key); } }; From 05651e792e327b5d6f52a096a61fa023e536e6c2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 14 Nov 2013 14:00:16 -0500 Subject: [PATCH 0176/1866] Adds test for skipping whole group --- tests/testgroupby.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/testgroupby.cpp b/tests/testgroupby.cpp index d499e8e8..8897d379 100644 --- a/tests/testgroupby.cpp +++ b/tests/testgroupby.cpp @@ -29,6 +29,20 @@ int main() 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'; From 9bac68db3dc02e6ede66701dc11cab82508c6f40 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 14 Nov 2013 15:05:46 -0500 Subject: [PATCH 0177/1866] Replaces pointers with references in groupby --- groupby.hpp | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index 0a3a67d2..52b44128 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -67,7 +67,7 @@ namespace iter { return KeyGroupPair( this->key_func(*this->sub_iter), Group( - this, + *this, this->key_func(*this->sub_iter))); } @@ -103,11 +103,11 @@ namespace iter { private: friend Iterator; friend class GroupIterator; - Iterator *owner; + Iterator & owner; key_func_ret key; mutable bool completed = false; - Group(Iterator *owner, key_func_ret key) : + Group(Iterator & owner, key_func_ret key) : owner(owner), key(key) { } @@ -133,17 +133,18 @@ namespace iter { class GroupIterator { private: - Iterator * owner; + Iterator & owner; const key_func_ret key; - const Group * group; + const Group & group; bool not_at_end() const { - return !this->owner->exhausted() && - this->owner->next_key() == this->key; + return !this->owner.exhausted() && + this->owner.next_key() == this->key; } public: - GroupIterator(Iterator * owner, const Group *group, + GroupIterator(Iterator & owner, + const Group & group, key_func_ret key) : owner(owner), key(key), @@ -156,27 +157,27 @@ namespace iter { if (this->not_at_end()) { return true; } else { - this->group->completed = true; + this->group.completed = true; return false; } } GroupIterator & operator++() { - this->owner->increment_iterator(); + this->owner.increment_iterator(); return *this; } contained_iter_ret operator*() const { - return this->owner->current(); + return this->owner.current(); } }; GroupIterator begin() const { - return GroupIterator(this->owner, this, key); + return GroupIterator(this->owner, *this, key); } GroupIterator end() const { - return GroupIterator(this->owner, this, key); + return GroupIterator(this->owner, *this, key); } }; From 4493e043ffea352ca13088e9841d61c82e80eaad Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 14 Nov 2013 15:20:53 -0500 Subject: [PATCH 0178/1866] Removes unnecessary Iterator& in GroupIterator --- groupby.hpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index 52b44128..5d1b34ee 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -133,20 +133,17 @@ namespace iter { class GroupIterator { private: - Iterator & owner; const key_func_ret key; const Group & group; bool not_at_end() const { - return !this->owner.exhausted() && - this->owner.next_key() == this->key; + return !this->group.owner.exhausted() && + this->group.owner.next_key() == this->key; } public: - GroupIterator(Iterator & owner, - const Group & group, + GroupIterator(const Group & group, key_func_ret key) : - owner(owner), key(key), group(group) { } @@ -163,21 +160,21 @@ namespace iter { } GroupIterator & operator++() { - this->owner.increment_iterator(); + this->group.owner.increment_iterator(); return *this; } contained_iter_ret operator*() const { - return this->owner.current(); + return this->group.owner.current(); } }; GroupIterator begin() const { - return GroupIterator(this->owner, *this, key); + return GroupIterator(*this, key); } GroupIterator end() const { - return GroupIterator(this->owner, *this, key); + return GroupIterator(*this, key); } }; From ea31fbf5dcf4c3476961e814faff056f678e5dd7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 14 Nov 2013 15:29:47 -0500 Subject: [PATCH 0179/1866] Make Group movable, not copyable --- groupby.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/groupby.hpp b/groupby.hpp index 5d1b34ee..38f5e6ac 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -123,8 +123,13 @@ namespace iter { + // can be move constructed, but not copied or move assigned Group () = delete; - Group (const Group &other) : + Group (const Group &) = delete; + Group & operator=(const Group &) = delete; + Group & operator=(Group &&) = delete; + + Group (Group && other) : owner(other.owner), key(other.key), completed(other.completed) { From 9df4a8198636755dfe822d2c9abfbd8b9ae7fd7f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 14 Nov 2013 15:41:05 -0500 Subject: [PATCH 0180/1866] adds comments explaining 'completed' --- groupby.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/groupby.hpp b/groupby.hpp index 38f5e6ac..c02e7a5f 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -105,6 +105,16 @@ namespace iter { friend class GroupIterator; Iterator & owner; key_func_ret key; + + // completed is set if a Group is iterated through + // completely. It is checked in the destructor, and + // if the Group has not been completed, the destructor + // exhausts it. This ensures that the next Group starts + // at the correct position when the user short-circuits + // iteration over a Group. + // The move constructor sets the rvalue's completed + // attribute to true, so its destructor doesn't do anything + // when called. mutable bool completed = false; Group(Iterator & owner, key_func_ret key) : From 8979c6e959f7c0fa06fd199ebcfc67fc93ddd5f4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 14 Nov 2013 21:48:44 -0500 Subject: [PATCH 0181/1866] Removes commented out bits from SConstruct --- tests/SConstruct | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/tests/SConstruct b/tests/SConstruct index ceb1f196..a28500f5 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -2,7 +2,7 @@ import platform import os env = Environment( - CXX='clang++', + CXX='c++', CXXFLAGS= ['-g', '-Wall', '-Wextra', '-pedantic', '-std=c++11', '-I/usr/local/include'], @@ -12,15 +12,6 @@ env = Environment( # allows highighting to print to terminal from compiler output env['ENV']['TERM'] = os.environ['TERM'] -# if on MAC, needs the linker flag for -stdlib=libc++ -# obselete with mavericks -""" if platform.system() == 'Darwin': - env['CXX'] += '-stdlib=libc++' - env['CXXFLAGS'].append('-stdlib=libc++') -""" - - - progs = Split( ''' cycle enumerate From 5cbc4a63cbc419463109f3736dcdfc2c8ffc8f42 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Thu, 14 Nov 2013 22:15:07 -0500 Subject: [PATCH 0182/1866] super special size() --- slice.hpp | 13 +++++++++++-- tests/testslice.cpp | 7 ++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/slice.hpp b/slice.hpp index 7e9759c6..a5b537bc 100644 --- a/slice.hpp +++ b/slice.hpp @@ -17,6 +17,15 @@ namespace iter { //template //Slice slice(Container &&); + template + size_t size(Container & container) { + return container.size(); + } + template + size_t size(T (&)[N]) { + return N; + } + template class Slice : public IterBase{ private: @@ -49,8 +58,8 @@ namespace iter { (start > stop && step >=0)){ this->stop = start; } - if (this->stop > static_cast(container.size())) { - this->stop = static_cast(container.size()); + if (this->stop > static_cast(size(container))) { + this->stop = static_cast(size(container)); } if (this->start < 0) { this->start = 0; diff --git a/tests/testslice.cpp b/tests/testslice.cpp index 6db6da85..80b7f15b 100644 --- a/tests/testslice.cpp +++ b/tests/testslice.cpp @@ -57,5 +57,10 @@ int main() { //invalid range returns two begin iters std::cout << i << std::endl; } - + std::cout<< "\nstatic array[1:8:2]\n"; + int arr[10] = {0,1,2,3,4,5,6,7,8,9}; + for (auto i : iter::slice(arr,1,8,2)) { + //invalid range returns two begin iters + std::cout << i << std::endl; + } } From 58d5432c2ec94c150474b9b07b3a7801098fc9aa Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Thu, 14 Nov 2013 22:28:05 -0500 Subject: [PATCH 0183/1866] awesome slice SFINAE --- slice.hpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/slice.hpp b/slice.hpp index a5b537bc..a6a0f59f 100644 --- a/slice.hpp +++ b/slice.hpp @@ -4,6 +4,7 @@ #include #include +#include namespace iter { @@ -16,11 +17,29 @@ namespace iter { //template //Slice slice(Container &&); + template + class has_size + { + typedef char one; + typedef long two; + template static one test( decltype(&C::size) ) ; + template static two test(...); + + + public: + enum { value = sizeof(test(0)) == sizeof(char) }; + }; template - size_t size(Container & container) { + typename std::enable_if::value,size_t>::type + size(Container & container) { return container.size(); } + template + typename std::enable_if::value,size_t>::type + size(Container & container) { + return std::distance(container.end(),container.begin()); + } template size_t size(T (&)[N]) { return N; From 3e3385256674290782ad8cdb849c748d49818891 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 14 Nov 2013 23:45:18 -0500 Subject: [PATCH 0184/1866] Support for initializer_list, uses stdbegin/end --- slice.hpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/slice.hpp b/slice.hpp index a6a0f59f..24b69e7c 100644 --- a/slice.hpp +++ b/slice.hpp @@ -6,6 +6,7 @@ #include #include + namespace iter { //Forward declarations of Slice and slice @@ -35,16 +36,20 @@ namespace iter { size(Container & container) { return container.size(); } + template typename std::enable_if::value,size_t>::type size(Container & container) { - return std::distance(container.end(),container.begin()); + return std::distance(std::begin(container), std::end(container)); } + template size_t size(T (&)[N]) { return N; } + + template class Slice : public IterBase{ private: @@ -153,6 +158,20 @@ namespace iter { return Slice( std::forward(container), 0, stop, 1); } + + template + Slice, DifferenceType> slice( + std::initializer_list && il, DifferenceType start, + DifferenceType stop, DifferenceType step=1) { + return Slice, DifferenceType>( + il, start, stop, step); + } + + template + Slice, DifferenceType> slice( + std::initializer_list && il, DifferenceType stop) { + return Slice, DifferenceType>(il, 0, stop, 1); + } } #endif //SLICE_HPP From 71ab631a3f883356615d7ce2eec6ae85e92fb5ac Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 14 Nov 2013 23:46:40 -0500 Subject: [PATCH 0185/1866] Adds initializer_list test for slice --- tests/testslice.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/testslice.cpp b/tests/testslice.cpp index 80b7f15b..cc19f455 100644 --- a/tests/testslice.cpp +++ b/tests/testslice.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -57,10 +58,17 @@ int main() { //invalid range returns two begin iters std::cout << i << std::endl; } + std::cout<< "\nstatic array[1:8:2]\n"; int arr[10] = {0,1,2,3,4,5,6,7,8,9}; for (auto i : iter::slice(arr,1,8,2)) { //invalid range returns two begin iters std::cout << i << std::endl; } + + std::cout << "\ninitializer list\n"; + for (auto i : iter::slice({1, 2, 4, 8, 16, 32, 64, 128}, 2, 6)) { + std::cout << i << '\n'; + } + } From 0f1bee3e970983d35d5a68bf12b3acbc1070d7b8 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Wed, 20 Nov 2013 15:05:39 -0500 Subject: [PATCH 0186/1866] Updated product to use std::begin, since container is const uses const overload --- product.hpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/product.hpp b/product.hpp index 6b47cfd2..42465b04 100644 --- a/product.hpp +++ b/product.hpp @@ -15,19 +15,20 @@ namespace iter { auto end = product_iter(containers...); return iterator_range(begin,end); } + //template struct product_iter { public: - using Iterator = decltype(std::declval().cbegin()); + using Iterator = decltype(std::begin(std::declval())); private: Iterator begin; Iterator mover; const Iterator end; public: product_iter(const Container & c) : - begin(c.cbegin()), - mover(c.cbegin()), - end(c.cend()){} + begin(std::begin(c)), + mover(std::begin(c)), + end(std::end(c)){} decltype(std::make_tuple(*mover)) operator*() //since you can't modify anything anyway it's ok to return a //tuple of whatever the iterator derefs to @@ -60,7 +61,7 @@ namespace iter { struct product_iter { public: - using Iterator = decltype(std::declval().cbegin()); + using Iterator = decltype(std::begin(std::declval())); private: Iterator begin; Iterator mover; @@ -73,9 +74,9 @@ namespace iter { return begin != end && inner_iter.is_not_empty_range(); } product_iter(const Container & c, const Containers & ... containers): - begin(c.cbegin()), - mover(c.cbegin()), - end(c.cend()), + begin(std::begin(c)), + mover(std::begin(c)), + end(std::end(c)), inner_iter(containers...){ no_empty_ranges = is_not_empty_range(); } From 62f2fb03514fbe7d87f2da0e8ae4457c81cf531e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 13:22:33 -0500 Subject: [PATCH 0187/1866] Adds test with range temporary for (auto i : enumerate(range(...))), something I've been meaning to do for a while. --- tests/testenumerate.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/testenumerate.cpp b/tests/testenumerate.cpp index a6b3adf9..498139e3 100644 --- a/tests/testenumerate.cpp +++ b/tests/testenumerate.cpp @@ -1,24 +1,28 @@ #include +#include #include #include #include using iter::enumerate; +using iter::range; int main() { - std::string s = "hello world"; - + 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; @@ -26,15 +30,23 @@ int main() { 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'; + } + return 0; } From c37c84a84a97c519943f503052df86674e88cfaf Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 13:24:55 -0500 Subject: [PATCH 0188/1866] Adds support for temporaries --- enumerate.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index ef367d52..8f900b1a 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -33,7 +33,7 @@ namespace iter { template class Enumerable : public IterBase{ - private: + public: Container & container; // The only thing allowed to directly instantiate an Enumerable is @@ -46,7 +46,7 @@ namespace iter { using typename IterBase::contained_iter_ret; - Enumerable(Container & container) : container(container) { } + Enumerable(Container && container) : container(container) { } public: // Value constructor for use only in the enumerate function @@ -113,7 +113,8 @@ namespace iter { template Enumerable> enumerate(std::initializer_list && il) { - return Enumerable>(il); + return Enumerable>( + std::forward>(il)); } } From 3c0cc9a6f96f84963dd0b112ee36e18309a1102e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 13:31:29 -0500 Subject: [PATCH 0189/1866] Restores privacy to enumerate --- enumerate.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enumerate.hpp b/enumerate.hpp index 8f900b1a..31fd282a 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -33,7 +33,7 @@ namespace iter { template class Enumerable : public IterBase{ - public: + private: Container & container; // The only thing allowed to directly instantiate an Enumerable is From 3c138e9f2fc9ac3484d9e8f6f24856b7544035d4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 13:38:48 -0500 Subject: [PATCH 0190/1866] Adds initializer_list test --- tests/testcycle.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/testcycle.cpp b/tests/testcycle.cpp index bd4e2d0b..72c88dd8 100644 --- a/tests/testcycle.cpp +++ b/tests/testcycle.cpp @@ -21,11 +21,21 @@ int main() { int array[] = {68, 69, 70}; for (auto i : cycle(array)) { std::cout << i << '\n'; - if (count == 100) { + if (count == 20) { break; } ++count; } + count = 0; + for (auto i : cycle({7, 8, 9})) { + std::cout << i << '\n'; + if (count == 20) { + break; + } + ++count; + } + + return 0; } From 5772be8f62753529e6b24f291bfc77951163e521 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 13:39:44 -0500 Subject: [PATCH 0191/1866] Adds support for initializer_list --- cycle.hpp | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/cycle.hpp b/cycle.hpp index a6aaa029..1890f229 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -13,14 +13,20 @@ namespace iter { class Cycle; template - Cycle cycle(Container &); + Cycle cycle(Container &&); + template + Cycle> cycle( + std::initializer_list &&); template class Cycle : public IterBase{ - private: + public: // The cycle function is the only thing allowed to create a Cycle - friend Cycle cycle(Container &); + friend Cycle cycle(Container &&); + template + friend Cycle> cycle( + std::initializer_list &&); using typename IterBase::contained_iter_type; @@ -29,7 +35,7 @@ namespace iter { Container & container; // Value constructor for use only in the cycle function - Cycle(Container & container) : container(container) { } + Cycle(Container && container) : container(container) { } Cycle () = delete; Cycle & operator=(const Cycle &) = delete; @@ -80,10 +86,16 @@ namespace iter { // Helper function to instantiate an Filter template - Cycle cycle(Container & container) { - return Cycle(container); + Cycle cycle(Container && container) { + return Cycle(std::forward(container)); } + template + Cycle> cycle(std::initializer_list && il) + { + return Cycle>( + std::forward>(il)); + } } #endif //ifndef CYCLE__H__ From cde655ae3d2f85b01eeba3933234cf7848874c63 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 13:55:24 -0500 Subject: [PATCH 0192/1866] formatting --- enumerate.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/enumerate.hpp b/enumerate.hpp index 31fd282a..1abcb748 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -40,7 +40,8 @@ namespace iter { // the enumerate function friend Enumerable enumerate(Container &&); template - friend Enumerable> enumerate(std::initializer_list &&); + friend Enumerable> enumerate( + std::initializer_list &&); using typename IterBase::contained_iter_type; From 77469bf1574c2894f021e77ffa138cebd9eeab6e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 15:05:44 -0500 Subject: [PATCH 0193/1866] Adds Range::Iterator::operator= to copy value --- range.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/range.hpp b/range.hpp index edd48505..07aa655f 100644 --- a/range.hpp +++ b/range.hpp @@ -85,6 +85,11 @@ namespace iter { step(step) { } + Iterator & operator=(const Iterator &other) { + this->value = other.value; + return *this; + } + T operator*() const { return this->value; } From ba0031d663fb7bc16de314afbbc9d4cc3fe3b3d0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 15:07:34 -0500 Subject: [PATCH 0194/1866] Adds test with temporary --- tests/testcycle.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/testcycle.cpp b/tests/testcycle.cpp index 72c88dd8..98987a77 100644 --- a/tests/testcycle.cpp +++ b/tests/testcycle.cpp @@ -1,9 +1,11 @@ #include +#include #include #include using iter::cycle; +using iter::range; int main() { std::vector vec = {2, 4, 6}; @@ -36,6 +38,15 @@ int main() { ++count; } + count = 0; + for (auto i : cycle(range(3))) { + std::cout << i << '\n'; + if (count == 20) { + break; + } + ++count; + } + return 0; } From a180961bae3d2ec5e7faa8e0393331c9f518d8fa Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 15:08:42 -0500 Subject: [PATCH 0195/1866] Adds support for temporaries --- cycle.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cycle.hpp b/cycle.hpp index 1890f229..8d4a5e95 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -5,6 +5,7 @@ #include #include +#include namespace iter { @@ -21,7 +22,7 @@ namespace iter { template class Cycle : public IterBase{ - public: + private: // The cycle function is the only thing allowed to create a Cycle friend Cycle cycle(Container &&); template @@ -61,7 +62,7 @@ namespace iter { Iterator & operator++() { ++this->sub_iter; // reset to beginning upon reaching the end - if (this->sub_iter == this->end) { + if (!(this->sub_iter != this->end)) { this->sub_iter = this->begin; } return *this; From f971d5029f9f033d6b820d2c585364b7f46196f6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 15:12:51 -0500 Subject: [PATCH 0196/1866] Adds test with const string --- tests/testcycle.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/testcycle.cpp b/tests/testcycle.cpp index 98987a77..d7c0f91b 100644 --- a/tests/testcycle.cpp +++ b/tests/testcycle.cpp @@ -47,6 +47,15 @@ int main() { ++count; } + count = 0; + const std::string s("hello"); + for (auto c : cycle(s)) { + std::cout << c << '\n'; + if (count == 20) { + break; + } + ++count; + } return 0; } From 3bd45410db736ba0916485ae3f9ef7ebc7b88a42 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 17:37:00 -0500 Subject: [PATCH 0197/1866] Adds test with initializer_list --- tests/testfilter.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/testfilter.cpp b/tests/testfilter.cpp index 63718646..a82b524f 100644 --- a/tests/testfilter.cpp +++ b/tests/testfilter.cpp @@ -49,5 +49,12 @@ int main() { } + 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'; + } + return 0; } From 62ad190e0cc9ab21dbc5863cb7b9c30a6e01e3be Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 17:39:34 -0500 Subject: [PATCH 0198/1866] Adds test with range(10) temp --- tests/testfilter.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/testfilter.cpp b/tests/testfilter.cpp index a82b524f..3d528e21 100644 --- a/tests/testfilter.cpp +++ b/tests/testfilter.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -48,6 +49,11 @@ int main() { 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 << "ever numbers in initializer_list\n"; for (auto i : filter([] (const int i) {return i % 2 == 0;}, From 8775a7551b08dd2403160d4cd75ffbcfd8b5d1b9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 17:41:49 -0500 Subject: [PATCH 0199/1866] Adds support for initializer_lists and temporaries --- filter.hpp | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/filter.hpp b/filter.hpp index 0af88a29..152f6d30 100644 --- a/filter.hpp +++ b/filter.hpp @@ -5,6 +5,7 @@ #include #include +#include namespace iter { @@ -13,24 +14,31 @@ namespace iter { class Filter; template - Filter filter(FilterFunc, Container &); + Filter filter(FilterFunc, Container &&); + + template + Filter> filter( + FilterFunc, std::initializer_list &&); template class Filter : IterBase{ - private: + public: Container & container; FilterFunc filter_func; // The filter function is the only thing allowed to create a Filter - friend Filter filter(FilterFunc, - Container &); + friend Filter filter( + FilterFunc, Container &&); + template + friend Filter> filter( + FilterFunc, std::initializer_list &&); using typename IterBase::contained_iter_type; using typename IterBase::contained_iter_ret; // Value constructor for use only in the filter function - Filter(FilterFunc filter_func, Container & container) : + Filter(FilterFunc filter_func, Container && container) : container(container), filter_func(filter_func) { } @@ -100,8 +108,9 @@ namespace iter { // Helper function to instantiate a Filter template Filter filter( - FilterFunc filter_func, Container & container) { - return Filter(filter_func, container); + FilterFunc filter_func, Container && container) { + return Filter( + filter_func, std::forward(container)); } namespace detail { @@ -126,9 +135,23 @@ namespace iter { template - auto filter(Container & container) -> - decltype(filter(detail::BoolTester(), container)) { - return filter(detail::BoolTester(), container); + auto filter(Container && container) -> + decltype(filter( + detail::BoolTester(), + std::forward(container))) { + return filter(detail::BoolTester(), + std::forward(container)); + } + + template + Filter> filter( + FilterFunc filter_func, + std::initializer_list && il) + { + return Filter>( + filter_func, + std::move(il)); + //std::forward>(il)); } } From beac28ee84c47182d86ae05032153c436fdef41f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 17:43:05 -0500 Subject: [PATCH 0200/1866] removes commented out line --- filter.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/filter.hpp b/filter.hpp index 152f6d30..55d6eb15 100644 --- a/filter.hpp +++ b/filter.hpp @@ -149,9 +149,7 @@ namespace iter { std::initializer_list && il) { return Filter>( - filter_func, - std::move(il)); - //std::forward>(il)); + filter_func, std::move(il)); } } From a0db1a993af03f9392cc68158c0e383c562fd002 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 17:44:11 -0500 Subject: [PATCH 0201/1866] replaces forward with move --- enumerate.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 1abcb748..851602c9 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -114,8 +114,7 @@ namespace iter { template Enumerable> enumerate(std::initializer_list && il) { - return Enumerable>( - std::forward>(il)); + return Enumerable>(std::move(il)); } } From f816d41e73dc8b87884a4ba9b35b41ebfa464e4f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 17:44:39 -0500 Subject: [PATCH 0202/1866] replaces forward with move --- cycle.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cycle.hpp b/cycle.hpp index 8d4a5e95..5cce0d91 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -94,8 +94,7 @@ namespace iter { template Cycle> cycle(std::initializer_list && il) { - return Cycle>( - std::forward>(il)); + return Cycle>(std::move(il)); } } From b63a6c63fcc7b10f2f7249b52266fc853ae9288d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 19:30:57 -0500 Subject: [PATCH 0203/1866] Adds test for initialization_list with default filter --- tests/testfilter.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/testfilter.cpp b/tests/testfilter.cpp index 3d528e21..006cc8d3 100644 --- a/tests/testfilter.cpp +++ b/tests/testfilter.cpp @@ -62,5 +62,10 @@ int main() { 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'; + } + return 0; } From 2fd239306156261dc30f12bc73b2497df4bfa7c5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 19:31:14 -0500 Subject: [PATCH 0204/1866] Adds support for single argument initialization_list filter --- filter.hpp | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/filter.hpp b/filter.hpp index 55d6eb15..5be53cb6 100644 --- a/filter.hpp +++ b/filter.hpp @@ -113,6 +113,15 @@ namespace iter { filter_func, std::forward(container)); } + template + Filter> filter( + FilterFunc filter_func, + std::initializer_list && il) + { + return Filter>( + filter_func, std::move(il)); + } + namespace detail { template @@ -139,17 +148,19 @@ namespace iter { decltype(filter( detail::BoolTester(), std::forward(container))) { - return filter(detail::BoolTester(), + return filter( + detail::BoolTester(), std::forward(container)); } - template - Filter> filter( - FilterFunc filter_func, - std::initializer_list && il) - { - return Filter>( - filter_func, std::move(il)); + template + auto filter(std::initializer_list && il) -> + decltype(filter( + detail::BoolTester>(), + std::move(il))) { + return filter( + detail::BoolTester>(), + std::move(il)); } } From 288b025357b197699647b285b7cf07fc57c0aa10 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 23:32:11 -0500 Subject: [PATCH 0205/1866] Adds range(10) temp test --- tests/testfilterfalse.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/testfilterfalse.cpp b/tests/testfilterfalse.cpp index 73a8e5eb..156bec0e 100644 --- a/tests/testfilterfalse.cpp +++ b/tests/testfilterfalse.cpp @@ -1,9 +1,11 @@ #include +#include #include #include using iter::filterfalse; +using iter::range; bool greater_than_four(int i) { return i > 4; @@ -58,5 +60,12 @@ int main() { 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'; + } + + return 0; } From 14838a46a997f8e7cd2b6e3a4c5915e73ad9d35a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 23:37:44 -0500 Subject: [PATCH 0206/1866] Adds temp test with default filter --- tests/testfilterfalse.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/testfilterfalse.cpp b/tests/testfilterfalse.cpp index 156bec0e..93be73d7 100644 --- a/tests/testfilterfalse.cpp +++ b/tests/testfilterfalse.cpp @@ -66,6 +66,10 @@ int main() { std::cout << i << '\n'; } + std::cout << "range(-1, 2)\n"; + for (auto i : filterfalse(range(-1, 2))) { + std::cout << i << '\n'; + } return 0; } From 70752f0e770a904f784cd07217457e52ee3b4b39 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 23:39:04 -0500 Subject: [PATCH 0207/1866] Adds temp test with default predicate --- tests/testfilter.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/testfilter.cpp b/tests/testfilter.cpp index 006cc8d3..0b0b4865 100644 --- a/tests/testfilter.cpp +++ b/tests/testfilter.cpp @@ -54,6 +54,11 @@ int main() { 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;}, From d03f33994c6f224370c967ab023cb1e92a899258 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 23:39:27 -0500 Subject: [PATCH 0208/1866] Adds support for temporaries --- filterfalse.hpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/filterfalse.hpp b/filterfalse.hpp index b18cca5c..3275f2ab 100644 --- a/filterfalse.hpp +++ b/filterfalse.hpp @@ -4,6 +4,8 @@ #include #include +#include + namespace iter { namespace detail { @@ -53,20 +55,26 @@ 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), container)) { + auto filterfalse(FilterFunc filter_func, Container && container) -> + decltype(filter( + detail::PredicateFlipper( + filter_func), + std::forward(container))) { return filter( detail::PredicateFlipper(filter_func), - container); + std::forward(container)); } // Single argument version, uses a BoolFlipper to reverse the truthiness // of an object template - auto filterfalse(Container & container) -> - decltype(filter(detail::BoolFlipper(), container)) { - return filter(detail::BoolFlipper(), container); + auto filterfalse(Container && container) -> + decltype(filter( + detail::BoolFlipper(), + std::forward(container))) { + return filter( + detail::BoolFlipper(), + std::forward(container)); } } From 365dd5f63ecd7d608ca5d960fcb166050d12d715 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 23:41:55 -0500 Subject: [PATCH 0209/1866] Adds test for initializer_list --- tests/testfilterfalse.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/testfilterfalse.cpp b/tests/testfilterfalse.cpp index 93be73d7..ca708f5a 100644 --- a/tests/testfilterfalse.cpp +++ b/tests/testfilterfalse.cpp @@ -71,5 +71,12 @@ int main() { 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'; + } + return 0; } From 33f5f9c4a1db8c5476c809d8efc03df8f66b7ccb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 23:45:51 -0500 Subject: [PATCH 0210/1866] Adds test for initializer_list with default predicate --- tests/testfilterfalse.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/testfilterfalse.cpp b/tests/testfilterfalse.cpp index ca708f5a..0ff0fad0 100644 --- a/tests/testfilterfalse.cpp +++ b/tests/testfilterfalse.cpp @@ -78,5 +78,10 @@ int main() { 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'; + } + return 0; } From df92bd654268ef9be677d46cb597f265975e582b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 23:46:09 -0500 Subject: [PATCH 0211/1866] Adds support for initializer_lists --- filterfalse.hpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/filterfalse.hpp b/filterfalse.hpp index 3275f2ab..4448e7d0 100644 --- a/filterfalse.hpp +++ b/filterfalse.hpp @@ -77,6 +77,31 @@ namespace iter { std::forward(container)); } + + + //specializations for initializer_lists + template + auto filterfalse(FilterFunc filter_func, std::initializer_list && container) -> + decltype(filter( + detail::PredicateFlipper>( + filter_func), + std::move(container))) { + return filter( + 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))) { + return filter( + detail::BoolFlipper>(), + std::move(container)); + } } #endif //#ifndef FILTER_FALSE__HPP__ From 71a8d306fa2f8b35eb5240f5867b4ea4efeeacea Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 23:50:09 -0500 Subject: [PATCH 0212/1866] Adds test with temp --- tests/testtakewhile.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/testtakewhile.cpp b/tests/testtakewhile.cpp index 59568fe2..9da89040 100644 --- a/tests/testtakewhile.cpp +++ b/tests/testtakewhile.cpp @@ -1,14 +1,21 @@ #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'; + } + return 0; } From 0162c442a25caf45c62cb800f59fce4b636c6210 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 23:51:39 -0500 Subject: [PATCH 0213/1866] Adds support for temporaries --- takewhile.hpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/takewhile.hpp b/takewhile.hpp index a41c6109..7cf3bf73 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -13,7 +13,7 @@ namespace iter { class TakeWhile; template - TakeWhile takewhile(FilterFunc, Container &); + TakeWhile takewhile(FilterFunc, Container &&); template class TakeWhile : IterBase{ @@ -22,14 +22,14 @@ namespace iter { FilterFunc filter_func; friend TakeWhile takewhile( - FilterFunc, Container &); + FilterFunc, Container &&); using typename IterBase::contained_iter_type; using typename IterBase::contained_iter_ret; // Value constructor for use only in the takewhile function - TakeWhile(FilterFunc filter_func, Container & container) : + TakeWhile(FilterFunc filter_func, Container && container) : container(container), filter_func(filter_func) { } @@ -99,8 +99,10 @@ namespace iter { // Helper function to instantiate a TakeWhile template TakeWhile takewhile( - FilterFunc filter_func, Container & container) { - return TakeWhile(filter_func, container); + FilterFunc filter_func, Container && container) { + return TakeWhile( + filter_func, + std::forward(container)); } } From ee77cd61c55cf1d3a67ab457c508056f39349c7b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 23:52:52 -0500 Subject: [PATCH 0214/1866] Adds test with temporary --- tests/testdropwhile.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/testdropwhile.cpp b/tests/testdropwhile.cpp index c29dde4b..5db34401 100644 --- a/tests/testdropwhile.cpp +++ b/tests/testdropwhile.cpp @@ -1,14 +1,20 @@ #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'; } + + for (auto i : dropwhile([] (int i) {return i < 5;}, range(10))) { + std::cout << i << '\n'; + } return 0; } From 9abd92582e788b8e11e6f1179a89718ea76250ad Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 23:54:20 -0500 Subject: [PATCH 0215/1866] Adds support for temporaries --- dropwhile.hpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index ab9dccdf..3fda7cde 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -13,7 +13,7 @@ namespace iter { class DropWhile; template - DropWhile dropwhile(FilterFunc, Container &); + DropWhile dropwhile(FilterFunc, Container &&); template class DropWhile : IterBase { @@ -22,7 +22,7 @@ namespace iter { FilterFunc filter_func; friend DropWhile dropwhile( - FilterFunc, Container &); + FilterFunc, Container &&); using typename IterBase::contained_iter_type; @@ -30,7 +30,7 @@ namespace iter { // Value constructor for use only in the dropwhile function - DropWhile(FilterFunc filter_func, Container & container) : + DropWhile(FilterFunc filter_func, Container && container) : container(container), filter_func(filter_func) { } @@ -97,8 +97,10 @@ namespace iter { // Helper function to instantiate a DropWhile template DropWhile dropwhile( - FilterFunc filter_func, Container & container) { - return DropWhile(filter_func, container); + FilterFunc filter_func, Container && container) { + return DropWhile( + filter_func, + std::forward(container)); } } From 2ed2144224b7777fb5cc4abac7739577b88df2f1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 Nov 2013 23:55:56 -0500 Subject: [PATCH 0216/1866] Adds test for initializer_list --- tests/testdropwhile.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/testdropwhile.cpp b/tests/testdropwhile.cpp index 5db34401..8413e291 100644 --- a/tests/testdropwhile.cpp +++ b/tests/testdropwhile.cpp @@ -16,5 +16,11 @@ int main() { 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'; + } + return 0; } From 74ff071268a1d7f5b55d07daf72d6f0fbf6dcc44 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 22 Nov 2013 00:05:49 -0500 Subject: [PATCH 0217/1866] Restores privacy --- filter.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/filter.hpp b/filter.hpp index 5be53cb6..75c23bc0 100644 --- a/filter.hpp +++ b/filter.hpp @@ -22,7 +22,7 @@ namespace iter { template class Filter : IterBase{ - public: + private: Container & container; FilterFunc filter_func; @@ -30,9 +30,9 @@ namespace iter { friend Filter filter( FilterFunc, Container &&); - template - friend Filter> filter( - FilterFunc, std::initializer_list &&); + template + friend Filter> filter( + FF, std::initializer_list &&); using typename IterBase::contained_iter_type; using typename IterBase::contained_iter_ret; From 02c543fa50affae8c9788ef4a2a76af335329b57 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 22 Nov 2013 00:06:47 -0500 Subject: [PATCH 0218/1866] Adds support for initializer_lists --- dropwhile.hpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/dropwhile.hpp b/dropwhile.hpp index 3fda7cde..1f13efc9 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -5,6 +5,7 @@ #include #include +#include namespace iter { @@ -15,6 +16,10 @@ namespace iter { template DropWhile dropwhile(FilterFunc, Container &&); + template + DropWhile> dropwhile( + FilterFunc, std::initializer_list &&); + template class DropWhile : IterBase { private: @@ -24,6 +29,10 @@ namespace iter { friend DropWhile dropwhile( FilterFunc, Container &&); + template + friend DropWhile> dropwhile( + FF, std::initializer_list &&); + using typename IterBase::contained_iter_type; using typename IterBase::contained_iter_ret; @@ -103,6 +112,14 @@ namespace iter { std::forward(container)); } + template + DropWhile> dropwhile( + FilterFunc filter_func, std::initializer_list && il) + { + return DropWhile>( + filter_func, + std::move(il)); + } } #endif //ifndef DROPWHILE__H__ From 7c4a44cb48d5b1f3ae41648840606e0fbb1ee7f4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 22 Nov 2013 00:08:36 -0500 Subject: [PATCH 0219/1866] Adds test for initializer_list --- tests/testtakewhile.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/testtakewhile.cpp b/tests/testtakewhile.cpp index 9da89040..6cbd6e17 100644 --- a/tests/testtakewhile.cpp +++ b/tests/testtakewhile.cpp @@ -17,5 +17,10 @@ int main() { 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'; + } + return 0; } From ba17f1a14b8e09425097b9b5e294f0a06360e5ea Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 22 Nov 2013 00:12:09 -0500 Subject: [PATCH 0220/1866] Adds support for initializer_lists --- takewhile.hpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/takewhile.hpp b/takewhile.hpp index 7cf3bf73..8531223f 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -5,6 +5,7 @@ #include #include +#include namespace iter { @@ -15,6 +16,10 @@ namespace iter { template TakeWhile takewhile(FilterFunc, Container &&); + template + TakeWhile> takewhile( + FilterFunc, std::initializer_list &&); + template class TakeWhile : IterBase{ private: @@ -24,6 +29,10 @@ namespace iter { friend TakeWhile takewhile( FilterFunc, Container &&); + template + friend TakeWhile> takewhile( + FF, std::initializer_list &&); + using typename IterBase::contained_iter_type; using typename IterBase::contained_iter_ret; @@ -105,6 +114,15 @@ namespace iter { std::forward(container)); } + template + TakeWhile> takewhile( + FilterFunc filter_func, std::initializer_list && il) + { + return TakeWhile>( + filter_func, + std::move(il)); + } + } #endif //ifndef TAKEWHILE__H__ From 79ca168830b1b2b4603a9f5bc3ebd94d7dcb486d Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Fri, 22 Nov 2013 14:46:41 -0500 Subject: [PATCH 0221/1866] added some tests --- tests/testcombinations.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/testcombinations.cpp b/tests/testcombinations.cpp index 422c088e..ad2919f8 100644 --- a/tests/testcombinations.cpp +++ b/tests/testcombinations.cpp @@ -17,13 +17,19 @@ int main() { for (auto j : i ) std::cout << j << " "; std::cout<{1,2,3,4},3)) { for (auto j : i ) std::cout << j << " "; std::cout< Date: Fri, 22 Nov 2013 14:55:33 -0500 Subject: [PATCH 0222/1866] added initializer_list support to combinations --- combinations.hpp | 18 +++++++++++++----- tests/testcombinations.cpp | 4 +--- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/combinations.hpp b/combinations.hpp index 8ef8939b..1ff9a991 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace iter { //Could try having antoher template for container to return (right now it's @@ -23,19 +24,26 @@ namespace iter { return iterator_range>(begin,end); } + template + iterator_range>> + combinations(std::initializer_list && container, size_t N) { + auto begin = combinations_iter>(container,N); + auto end = combinations_iter>(container,N); + return {begin,end}; + } template struct combinations_iter { private: const Container & items; - std::vector indicies; + std::vector indicies; bool not_done = true; public: //Holy shit look at this typedef using item_t = typename std::remove_const< - typename std::remove_reference::type>::type; + typename std::remove_reference::type>::type; combinations_iter(const Container & i, size_t N) : items(i),indicies(N) { @@ -45,8 +53,8 @@ namespace iter { } size_t inc = 0; for (auto & iter : indicies) { - if (items.cbegin() + inc != items.cend()) { - iter = items.cbegin()+inc; + if (std::begin(items) + inc != std::end(items)) { + iter = std::begin(items)+inc; ++inc; } else { @@ -74,7 +82,7 @@ namespace iter { //index and the end of indicies is >= the distance between //the item and end of item if ((*iter + std::distance(indicies.rbegin(),iter)) == - items.cend()) { + std::end(items)) { if ( (iter + 1) != indicies.rend()) { size_t inc = 1; for (auto down = iter; down != indicies.rbegin()-1;--down) { diff --git a/tests/testcombinations.cpp b/tests/testcombinations.cpp index ad2919f8..2576dc94 100644 --- a/tests/testcombinations.cpp +++ b/tests/testcombinations.cpp @@ -25,11 +25,9 @@ int main() { for (auto j : i ) std::cout << j << " "; std::cout<{1,2,3,4},3)) { + for (auto i : combinations({1,2,3,4},3)) { for (auto j : i ) std::cout << j << " "; std::cout< Date: Fri, 22 Nov 2013 15:14:53 -0500 Subject: [PATCH 0223/1866] Added initializer_list support to combinations_with_replacement --- combinations_with_replacement.hpp | 17 ++++++++++++----- tests/testcombinations_with_replacement.cpp | 15 +++++++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index 043e0cf2..07aacf85 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -24,19 +24,26 @@ namespace iter { return iterator_range>(begin,end); } - template + template + iterator_range>> + combinations_with_replacement(std::initializer_list && container, size_t N) { + auto begin = combinations_with_replacement_iter>(container, N); + auto end = combinations_with_replacement_iter>(container, N); + return {begin,end}; + } + template struct combinations_with_replacement_iter { private: const Container & items; - std::vector indicies; + std::vector indicies; bool not_done = true; public: //Holy shit look at this typedef using item_t = typename std::remove_const< - typename std::remove_reference::type>::type; + typename std::remove_reference::type>::type; combinations_with_replacement_iter(const Container & i, size_t N) : items(i), indicies(N) { @@ -44,7 +51,7 @@ namespace iter { not_done = false; return; } - for (auto & iter : indicies) iter = items.cbegin(); + for (auto & iter : indicies) iter = std::begin(items); } //technically should be a dynarray std::vector operator*()const @@ -62,7 +69,7 @@ namespace iter { { for (auto iter = indicies.rbegin(); iter != indicies.rend(); ++iter) { ++(*iter); - if (*iter == items.cend()) { + if (*iter == std::end(items)) { if ( (iter + 1) != indicies.rend()) { for (auto down = iter; down != indicies.rbegin()-1;--down) { (*down) = (*(iter + 1)) + 1; diff --git a/tests/testcombinations_with_replacement.cpp b/tests/testcombinations_with_replacement.cpp index 9d714e0c..40fbad82 100644 --- a/tests/testcombinations_with_replacement.cpp +++ b/tests/testcombinations_with_replacement.cpp @@ -14,5 +14,20 @@ int main() { for (auto j : i ) std::cout << j << " "; std::cout< Date: Fri, 22 Nov 2013 15:30:46 -0500 Subject: [PATCH 0224/1866] permutations works with initializer_lists --- permutations.hpp | 18 +++++++++++++++--- tests/testpermutations.cpp | 7 +++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/permutations.hpp b/permutations.hpp index 839452c9..d9a65e2d 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -3,6 +3,8 @@ #include "iterator_range.hpp" #include +#include +#include namespace iter { template @@ -15,24 +17,34 @@ namespace iter { permutation_iter(container), permutation_iter()); } + //since initializer_list doesn't have bidir iters this is a hack + //to get it to work by using a vector in its place + template + iterator_range>> + permutations (std::initializer_list && container) { + std::vector begin(std::begin(container),std::end(container)); + return {permutation_iter>(container), + permutation_iter>()}; + } + template struct permutation_iter { Container container; - using Iterator = decltype(container.begin()); + using Iterator = decltype(std::begin(container)); bool is_not_last = true; permutation_iter(){} permutation_iter(const Container & c) : container(c) { //sort first so you can get every permutation - std::sort(container.begin(),container.end()); + std::sort(std::begin(container),std::end(container)); } const Container & operator*() { return container; } permutation_iter & operator++() { - is_not_last = std::next_permutation(container.begin(),container.end()); + is_not_last = std::next_permutation(std::begin(container),std::end(container)); return *this; } bool operator!=(const permutation_iter &) { diff --git a/tests/testpermutations.cpp b/tests/testpermutations.cpp index aa72c98a..adeeca06 100644 --- a/tests/testpermutations.cpp +++ b/tests/testpermutations.cpp @@ -27,5 +27,12 @@ int main() { } std::cout << std::endl; } + //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; + } return 0; } From 46e39f725a436ab98aad2f10d9c6beccff7217aa Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Fri, 22 Nov 2013 15:35:29 -0500 Subject: [PATCH 0225/1866] powerset initializer_list supoport --- powerset.hpp | 11 +++++++++++ tests/testpowerset.cpp | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/powerset.hpp b/powerset.hpp index 52398325..58e7cdfc 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -3,6 +3,7 @@ #include "iterator_range.hpp" #include "combinations.hpp" +#include namespace iter { template @@ -17,6 +18,16 @@ namespace iter { return iterator_range>(begin,end); } + template + iterator_range>> + powerset(std::initializer_list && container) + { + auto begin = powerset_iter>(container); + auto end = powerset_iter>(container); + return {begin,end}; + } + + template struct powerset_iter { private: diff --git a/tests/testpowerset.cpp b/tests/testpowerset.cpp index 23249f42..10f92c52 100644 --- a/tests/testpowerset.cpp +++ b/tests/testpowerset.cpp @@ -10,5 +10,10 @@ int main() { for (auto i : v) std::cout << i << " "; std::cout << std::endl; } + for (auto v : powerset({1,2,3,4})) { + for (auto i : v) std::cout << i << " "; + std::cout << std::endl; + } + return 0; } From f0e655d49bc6a3ef945aeaa04f1239bd50f74a5f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 22 Nov 2013 16:08:16 -0500 Subject: [PATCH 0226/1866] Adds tests for temporaries --- tests/testgroupby.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/testgroupby.cpp b/tests/testgroupby.cpp index 8897d379..19af7ad1 100644 --- a/tests/testgroupby.cpp +++ b/tests/testgroupby.cpp @@ -53,6 +53,15 @@ int main() 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'; + } + return 0; } From f441c5aa8573a85fe471a17426dce36fcc677a7a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 22 Nov 2013 16:09:00 -0500 Subject: [PATCH 0227/1866] Adds support for temporaries --- groupby.hpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index c02e7a5f..49dd1b0d 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -12,7 +12,7 @@ namespace iter { class GroupBy; template - GroupBy groupby(Container &, KeyFunc); + GroupBy groupby(Container &&, KeyFunc); template class GroupBy : IterBase { @@ -21,7 +21,7 @@ namespace iter { KeyFunc key_func; // The filter function is the only thing allowed to create a Filter - friend GroupBy groupby(Container &, KeyFunc); + friend GroupBy groupby(Container &&, KeyFunc); using typename IterBase::contained_iter_type; @@ -31,7 +31,7 @@ namespace iter { decltype(std::declval()( std::declval())); - GroupBy(Container & container, KeyFunc key_func) : + GroupBy(Container && container, KeyFunc key_func) : container(container), key_func(key_func) { } @@ -213,8 +213,10 @@ namespace iter { template GroupBy groupby( - Container & container, KeyFunc key_func) { - return GroupBy(container, key_func); + Container && container, KeyFunc key_func) { + return GroupBy( + std::forward(container), + key_func); } template @@ -230,9 +232,11 @@ namespace iter { }; template - auto groupby(Container & container) -> - decltype(groupby(container, ItemReturner())) { - return groupby(container, ItemReturner()); + auto groupby(Container && container) -> + decltype(groupby(std::forward(container), + ItemReturner())) { + return groupby(std::forward(container), + ItemReturner()); } } From 09fa6c2b56be40e1b2e42e3bf463187f0f1779c0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 22 Nov 2013 16:19:04 -0500 Subject: [PATCH 0228/1866] Makes GroupBy movable, non-copyable --- groupby.hpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index 49dd1b0d..021afdfb 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -35,11 +35,14 @@ namespace iter { container(container), key_func(key_func) { } - GroupBy () = delete; - GroupBy & operator=(const GroupBy &) = delete; public: - GroupBy(const GroupBy &) = default; + GroupBy () = delete; + GroupBy(const GroupBy &) = delete; + GroupBy& operator=(const GroupBy &) = delete; + + GroupBy (GroupBy &&) = default; + GroupBy & operator=(GroupBy &&) = default; class Iterator; class Group; @@ -131,14 +134,12 @@ namespace iter { } } - - - // can be move constructed, but not copied or move assigned + // movable, non-copyable Group () = delete; Group (const Group &) = delete; Group & operator=(const Group &) = delete; - Group & operator=(Group &&) = delete; + Group & operator=(Group &&) = default; Group (Group && other) : owner(other.owner), key(other.key), From 66041a195393d3f91ff979d4cfaefc6e40c8da02 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 22 Nov 2013 17:23:18 -0500 Subject: [PATCH 0229/1866] Adds test for initializer_list with default key --- tests/testgroupby.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/testgroupby.cpp b/tests/testgroupby.cpp index 19af7ad1..c38687fc 100644 --- a/tests/testgroupby.cpp +++ b/tests/testgroupby.cpp @@ -61,6 +61,15 @@ int main() } 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'; + } return 0; From 14fb16b25d5e9a66e58d565b35904556eb21884c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 22 Nov 2013 17:33:33 -0500 Subject: [PATCH 0230/1866] Adds test with initializer_list and defalt Key --- tests/testgroupby.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/testgroupby.cpp b/tests/testgroupby.cpp index c38687fc..c796e215 100644 --- a/tests/testgroupby.cpp +++ b/tests/testgroupby.cpp @@ -70,6 +70,16 @@ int main() } 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'; + } return 0; From a3f535f24bbf873aead82489a76c138bec81e579 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 22 Nov 2013 17:33:51 -0500 Subject: [PATCH 0231/1866] Adds support for initializer_lists --- groupby.hpp | 49 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index 021afdfb..1abc2b93 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -5,6 +5,7 @@ #include #include +#include namespace iter { @@ -14,15 +15,22 @@ namespace iter { template GroupBy groupby(Container &&, KeyFunc); + template + GroupBy, KeyFunc> groupby( + std::initializer_list &&, KeyFunc); + template class GroupBy : IterBase { private: Container & container; KeyFunc key_func; - // The filter function is the only thing allowed to create a Filter friend GroupBy groupby(Container &&, KeyFunc); + template + friend GroupBy, KF> groupby( + std::initializer_list &&, KF); + using typename IterBase::contained_iter_type; using typename IterBase::contained_iter_ret; @@ -212,14 +220,8 @@ namespace iter { }; - template - GroupBy groupby( - Container && container, KeyFunc key_func) { - return GroupBy( - std::forward(container), - key_func); - } - + // Takes something and returns it, used for default key of comparing + // items in the sequence directly template class ItemReturner { private: @@ -232,6 +234,16 @@ namespace iter { } }; + + template + GroupBy groupby( + Container && container, KeyFunc key_func) { + return GroupBy( + std::forward(container), + key_func); + } + + template auto groupby(Container && container) -> decltype(groupby(std::forward(container), @@ -240,6 +252,25 @@ namespace iter { ItemReturner()); } + + template + GroupBy, KeyFunc> groupby( + std::initializer_list && il, KeyFunc key_func) { + return GroupBy, KeyFunc>( + std::move(il), + key_func); + } + + + template + auto groupby(std::initializer_list && il) -> + decltype(groupby(std::move(il), + ItemReturner>())) { + return groupby( + std::move(il), + ItemReturner>()); + } + } From 72a8fe6229f3b9f0a6d97339c338d7ccc4659cdc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 22 Nov 2013 20:45:21 -0500 Subject: [PATCH 0232/1866] Adds test with two ranges zipped together (fails) --- tests/testzip.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/testzip.cpp b/tests/testzip.cpp index eb0ef476..65254030 100644 --- a/tests/testzip.cpp +++ b/tests/testzip.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -25,6 +26,11 @@ int main() { 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'; + } } //Aaron's test { @@ -81,6 +87,10 @@ int main() { << std::get<2>(e) << std::endl; } } + + + + return 0; } From adcd4c06c3445e58d2b7f8fb845606839f8e3c06 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Fri, 22 Nov 2013 21:00:52 -0500 Subject: [PATCH 0233/1866] changed std::tie to std::forward_as_tuple --- zip.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/zip.hpp b/zip.hpp index 909e03f4..200a9328 100644 --- a/zip.hpp +++ b/zip.hpp @@ -34,9 +34,9 @@ namespace iter { zip_iter(const Iterator & i) : iter(i){ } - auto operator*() -> decltype(std::tie(*iter)) + auto operator*() -> decltype(std::forward_as_tuple(*iter)) { - return std::tie(*iter); + return std::forward_as_tuple(*iter); } zip_iter & operator++() { ++iter; @@ -60,9 +60,9 @@ namespace iter { zip_iter(const First & f, const Second & s) : iter1(f),iter2(s) { } - auto operator*() -> decltype(std::tie(*iter1,*iter2)) + auto operator*() -> decltype(std::forward_as_tuple(*iter1,*iter2)) { - return std::tie(*iter1,*iter2); + return std::forward_as_tuple(*iter1,*iter2); } zip_iter & operator++() { ++iter1; @@ -84,7 +84,7 @@ namespace iter { public: using elem_type = decltype(*iter); using tuple_type = - decltype(std::tuple_cat(std::tie(*iter),*inner_iter)); + decltype(std::tuple_cat(std::forward_as_tuple(*iter),*inner_iter)); zip_iter(const First & f, const Rest & ... rest) : iter(f), @@ -93,7 +93,7 @@ namespace iter { tuple_type operator*() { - return std::tuple_cat(std::tie(*iter),*inner_iter); + return std::tuple_cat(std::forward_as_tuple(*iter),*inner_iter); } zip_iter & operator++() { From 84d17cc4f11a220732b708ac4f5d4307f52ecc67 Mon Sep 17 00:00:00 2001 From: Aaron Josephs Date: Fri, 22 Nov 2013 21:12:53 -0500 Subject: [PATCH 0234/1866] Fixed include in slice --- slice.hpp | 1 + tests/testcommand_chains.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/slice.hpp b/slice.hpp index 24b69e7c..5f1d289f 100644 --- a/slice.hpp +++ b/slice.hpp @@ -5,6 +5,7 @@ #include #include +#include namespace iter { diff --git a/tests/testcommand_chains.cpp b/tests/testcommand_chains.cpp index 7bc48d2d..76aca6f4 100644 --- a/tests/testcommand_chains.cpp +++ b/tests/testcommand_chains.cpp @@ -31,6 +31,7 @@ int main() { } } std::cout << std::endl; + /* { std::vector vec1{1,2,3,4,5,6}; std::vector vec2{7,8,9,10}; @@ -41,6 +42,7 @@ int main() { << std::get<1>(t) << std::endl; } } + */ std::cout << std::endl; { std::vector vec1{1,2,3,4,5,6}; From 04c9017b86af6b2926d5df975cfffef1b820ce11 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 22 Nov 2013 21:19:05 -0500 Subject: [PATCH 0235/1866] Adds test with temps --- tests/testimap.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/testimap.cpp b/tests/testimap.cpp index 60f8ede0..328307b0 100644 --- a/tests/testimap.cpp +++ b/tests/testimap.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -32,5 +33,9 @@ int main() { std::cout << i << '\n'; } + for (auto i : imap([] (const int x) { return x*x; }, iter::range(10))) { + std::cout << i << '\n'; + } + return 0; } From 70ffb5471442141220cb83c13edb7238d5baee77 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 22 Nov 2013 21:21:31 -0500 Subject: [PATCH 0236/1866] Adds support for temps --- imap.hpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/imap.hpp b/imap.hpp index 781679a9..0d3424a9 100644 --- a/imap.hpp +++ b/imap.hpp @@ -67,12 +67,12 @@ namespace iter { class IMap; template - IMap imap(MapFunc, Containers &...); + IMap imap(MapFunc, Containers &&...); template class IMap { // The imap function is the only thing allowed to create a IMap - friend IMap imap(MapFunc, Containers & ...); + friend IMap imap(MapFunc, Containers && ...); // The type returned when dereferencing the Containers...::Iterator // XXX depends on zip using iterator_range. would be nice if it didn't @@ -87,9 +87,9 @@ namespace iter { Zipped zipped; // Value constructor for use only in the imap function - IMap(MapFunc map_func, Containers & ... containers) : + IMap(MapFunc map_func, Containers && ... containers) : map_func(map_func), - zipped(zip(containers...)) + zipped(zip(std::forward(containers)...)) { } IMap () = delete; IMap & operator=(const IMap &) = delete; @@ -137,8 +137,10 @@ namespace iter { // Helper function to instantiate a IMap template IMap imap( - MapFunc map_func, Containers & ... containers) { - return IMap(map_func, containers...); + MapFunc map_func, Containers && ... containers) { + return IMap( + map_func, + std::forward(containers)...); } } From 07ab93d5ce5d2b61f7add4b800efaeb34cc74076 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 22 Nov 2013 23:09:45 -0500 Subject: [PATCH 0237/1866] Gets rid of template specialization to allow correct deduction --- unique_everseen.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unique_everseen.hpp b/unique_everseen.hpp index 52632636..53250b2d 100644 --- a/unique_everseen.hpp +++ b/unique_everseen.hpp @@ -27,7 +27,7 @@ namespace iter } else return false; }; - return filter(func,std::forward(container)); + return filter(func,std::forward(container)); } } From ef17afec48ba01bf1311b245d5cb9f05fbd1e74a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 22 Nov 2013 23:11:07 -0500 Subject: [PATCH 0238/1866] Gets rid of template specialization to allow correct deduction --- unique_justseen.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/unique_justseen.hpp b/unique_justseen.hpp index c50ba1e0..296c0977 100644 --- a/unique_justseen.hpp +++ b/unique_justseen.hpp @@ -25,8 +25,7 @@ namespace iter return *(++last) != e; } }; - //return filter(func,std::forward(container)); - return filter(func,std::forward(container)); + return filter(func,std::forward(container)); } } From 70283426b7c6b960d659c4b094461a7b6cec5ebd Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 22 Nov 2013 23:23:04 -0500 Subject: [PATCH 0239/1866] Removes include of iterbase from itertools.hpp --- itertools.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/itertools.hpp b/itertools.hpp index 4aecb577..b5a87d5d 100644 --- a/itertools.hpp +++ b/itertools.hpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include From f8807d24ef9f785779e2f01a52f8d8e66a7db473 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 24 Nov 2013 23:19:12 -0500 Subject: [PATCH 0240/1866] Adds test with temporary --- tests/testcompress.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/testcompress.cpp b/tests/testcompress.cpp index 76dfccaf..22da18ba 100644 --- a/tests/testcompress.cpp +++ b/tests/testcompress.cpp @@ -1,9 +1,11 @@ #include +#include #include #include using iter::compress; +using iter::range; template void testcase(std::vector data_vec, @@ -30,6 +32,10 @@ int main(void) std::cout << "Should print 2\n"; testcase(ivec, bvec3); + for (auto i : compress(range(10), bvec)) { + std::cout << i << '\n'; + } + return 0; } From 279cd2d1aaaa7cf6bf6ade4464c22681ef8f1d13 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 24 Nov 2013 23:21:57 -0500 Subject: [PATCH 0241/1866] Adds description to temp test --- tests/testcompress.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/testcompress.cpp b/tests/testcompress.cpp index 22da18ba..8335ad28 100644 --- a/tests/testcompress.cpp +++ b/tests/testcompress.cpp @@ -32,6 +32,7 @@ int main(void) 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'; } From f0b958067afaeea0e9a80d68f68340f4bd0236cb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 24 Nov 2013 23:23:12 -0500 Subject: [PATCH 0242/1866] Adds support for temporaries --- compress.hpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/compress.hpp b/compress.hpp index ff64bb9d..20d96f45 100644 --- a/compress.hpp +++ b/compress.hpp @@ -3,7 +3,6 @@ #include - #include namespace iter { @@ -13,7 +12,7 @@ namespace iter { class Compressed; template - Compressed compress(Container &, Selector &); + Compressed compress(Container &&, Selector &&); template @@ -25,7 +24,7 @@ namespace iter { // The only thing allowed to directly instantiate an Compressed is // the compress function friend Compressed compress( - Container &, Selector &); + Container &&, Selector &&); using typename IterBase::contained_iter_type; @@ -35,7 +34,7 @@ namespace iter { using selector_iter_type = decltype(std::begin(selectors)); // Value constructor for use only in the compress function - Compressed(Container & container, Selector & selectors) : + Compressed(Container && container, Selector && selectors) : container(container), selectors(selectors) { } @@ -111,8 +110,10 @@ namespace iter { // Helper function to instantiate an Compressed template Compressed compress( - Container & container, Selector & selectors) { - return Compressed(container, selectors); + Container && container, Selector && selectors) { + return Compressed( + std::forward(container), + std::forward(selectors)); } } From 0d38735709a5fd383a89539add93e890ac96edea Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 24 Nov 2013 23:37:31 -0500 Subject: [PATCH 0243/1866] Adds test with init list for data --- tests/testcompress.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/testcompress.cpp b/tests/testcompress.cpp index 8335ad28..e6e6659f 100644 --- a/tests/testcompress.cpp +++ b/tests/testcompress.cpp @@ -37,6 +37,10 @@ int main(void) 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'; + } return 0; } From 8566bcacdbb291ec7f8202ae66311f6a7be63405 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 24 Nov 2013 23:37:48 -0500 Subject: [PATCH 0244/1866] Adds support for init list for data --- compress.hpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/compress.hpp b/compress.hpp index 20d96f45..e183e53c 100644 --- a/compress.hpp +++ b/compress.hpp @@ -14,6 +14,10 @@ namespace iter { template Compressed compress(Container &&, Selector &&); + template + Compressed, Selector> compress( + std::initializer_list &&, Selector &&); + template class Compressed : public IterBase { @@ -25,6 +29,9 @@ namespace iter { // the compress function friend Compressed compress( Container &&, Selector &&); + template + friend Compressed, Sel> compress( + std::initializer_list &&, Sel &&); using typename IterBase::contained_iter_type; @@ -116,6 +123,13 @@ namespace iter { std::forward(selectors)); } + template + Compressed, Selector> compress( + std::initializer_list && il, Selector && selectors) { + return Compressed, Selector>( + std::move(il), + std::forward(selectors)); + } } #endif //ifndef COMPRESS__H__ From 8874e18d1fa750a97b25927be0a3ebbe57b41bec Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 24 Nov 2013 23:46:54 -0500 Subject: [PATCH 0245/1866] Adds test for initlist with seletors --- tests/testcompress.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/testcompress.cpp b/tests/testcompress.cpp index e6e6659f..2b3f97bd 100644 --- a/tests/testcompress.cpp +++ b/tests/testcompress.cpp @@ -42,5 +42,11 @@ int main(void) 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'; + } + + return 0; } From 9371715a2a0b1203ec23ab05aae8959a5932f4ba Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 24 Nov 2013 23:47:12 -0500 Subject: [PATCH 0246/1866] Adds support for init list with selectors --- compress.hpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/compress.hpp b/compress.hpp index e183e53c..e732c47e 100644 --- a/compress.hpp +++ b/compress.hpp @@ -4,6 +4,7 @@ #include #include +#include namespace iter { @@ -18,6 +19,10 @@ namespace iter { Compressed, Selector> compress( std::initializer_list &&, Selector &&); + template + Compressed> compress( + Container &&, std::initializer_list &&); + template class Compressed : public IterBase { @@ -29,10 +34,15 @@ namespace iter { // the compress function friend Compressed compress( Container &&, Selector &&); + template friend Compressed, Sel> compress( std::initializer_list &&, Sel &&); + template + friend Compressed> compress( + Con &&, std::initializer_list &&); + using typename IterBase::contained_iter_type; using typename IterBase::contained_iter_ret; @@ -130,6 +140,14 @@ namespace iter { std::move(il), std::forward(selectors)); } + + template + Compressed> compress( + Container && container, std::initializer_list && il) { + return Compressed>( + std::forward(container), + std::move(il)); + } } #endif //ifndef COMPRESS__H__ From a903c302922445c142c820bc130e958ca2d4e231 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 24 Nov 2013 23:56:02 -0500 Subject: [PATCH 0247/1866] Addes test for two init lists --- tests/testcompress.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/testcompress.cpp b/tests/testcompress.cpp index 2b3f97bd..ebbeb642 100644 --- a/tests/testcompress.cpp +++ b/tests/testcompress.cpp @@ -46,6 +46,13 @@ int main(void) 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'; + } return 0; From 7f16a658713707de13969fb69953638385288324 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 24 Nov 2013 23:56:18 -0500 Subject: [PATCH 0248/1866] Adds support for two init lists --- compress.hpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/compress.hpp b/compress.hpp index e732c47e..1d3df13e 100644 --- a/compress.hpp +++ b/compress.hpp @@ -23,6 +23,9 @@ namespace iter { Compressed> compress( Container &&, std::initializer_list &&); + template + Compressed, std::initializer_list> compress( + std::initializer_list &&, std::initializer_list &&); template class Compressed : public IterBase { @@ -43,6 +46,10 @@ namespace iter { friend Compressed> compress( Con &&, std::initializer_list &&); + template + friend Compressed, std::initializer_list> compress( + std::initializer_list &&, std::initializer_list &&); + using typename IterBase::contained_iter_type; using typename IterBase::contained_iter_ret; @@ -135,18 +142,27 @@ namespace iter { template Compressed, Selector> compress( - std::initializer_list && il, Selector && selectors) { + std::initializer_list && data, Selector && selectors) { return Compressed, Selector>( - std::move(il), + std::move(data), std::forward(selectors)); } template Compressed> compress( - Container && container, std::initializer_list && il) { + Container && container, std::initializer_list && selectors) { return Compressed>( std::forward(container), - std::move(il)); + std::move(selectors)); + } + + template + Compressed, std::initializer_list> compress( + std::initializer_list && data, + std::initializer_list && selectors) { + return Compressed, std::initializer_list>( + std::move(data), + std::move(selectors)); } } From 105aa1d890e5337c923350cdc82dfbda73e3bbf7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 24 Nov 2013 23:58:06 -0500 Subject: [PATCH 0249/1866] Fixes skip_failures The check also needed to compare the current selector iterator to the end of the selectors iterable. The missing check was causing some warnings in valgrind about conditional jumps on uninitialized values. --- compress.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/compress.hpp b/compress.hpp index 1d3df13e..20be94d5 100644 --- a/compress.hpp +++ b/compress.hpp @@ -83,6 +83,7 @@ namespace iter { void skip_failures() { while (this->sub_iter != this->sub_end && + this->selector_iter != this->selector_end && !*this->selector_iter) { this->increment_iterators(); } From d4f79321842dd584f799a7d51d3e066a2cdb7cac Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 25 Nov 2013 00:18:49 -0500 Subject: [PATCH 0250/1866] Replaces <> with "" for local includes --- chain.hpp | 1 + compress.hpp | 2 +- cycle.hpp | 2 +- enumerate.hpp | 2 +- filter.hpp | 2 +- filterfalse.hpp | 4 ++-- groupby.hpp | 2 +- grouper.hpp | 1 + imap.hpp | 2 +- itertools.hpp | 58 ++++++++++++++++++++++----------------------- moving_section.hpp | 1 + permutations.hpp | 1 + powerset.hpp | 1 + product.hpp | 3 ++- slice.hpp | 2 +- sorted.hpp | 2 +- takewhile.hpp | 2 +- tests/SConstruct | 2 +- unique_everseen.hpp | 1 + unique_justseen.hpp | 1 + zip_longest.hpp | 3 ++- 21 files changed, 52 insertions(+), 43 deletions(-) diff --git a/chain.hpp b/chain.hpp index 2c536a27..d54b1426 100644 --- a/chain.hpp +++ b/chain.hpp @@ -2,6 +2,7 @@ #define CHAIN_HPP #include "iterator_range.hpp" + #include #include diff --git a/compress.hpp b/compress.hpp index 20be94d5..b97db516 100644 --- a/compress.hpp +++ b/compress.hpp @@ -1,7 +1,7 @@ #ifndef COMPRESS__H__ #define COMPRESS__H__ -#include +#include "iterbase.hpp" #include #include diff --git a/cycle.hpp b/cycle.hpp index 5cce0d91..53da8619 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -1,7 +1,7 @@ #ifndef CYCLE__H__ #define CYCLE__H__ -#include +#include "iterbase.hpp" #include #include diff --git a/enumerate.hpp b/enumerate.hpp index 851602c9..12bf9af8 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -1,7 +1,7 @@ #ifndef ENUMERABLE__H__ #define ENUMERABLE__H__ -#include +#include "iterbase.hpp" #include #include diff --git a/filter.hpp b/filter.hpp index 75c23bc0..3e51d2d9 100644 --- a/filter.hpp +++ b/filter.hpp @@ -1,7 +1,7 @@ #ifndef FILTER__H__ #define FILTER__H__ -#include +#include "iterbase.hpp" #include #include diff --git a/filterfalse.hpp b/filterfalse.hpp index 4448e7d0..02c3b9b7 100644 --- a/filterfalse.hpp +++ b/filterfalse.hpp @@ -1,8 +1,8 @@ #ifndef FILTER_FALSE__HPP__ #define FILTER_FALSE__HPP__ -#include -#include +#include "iterbase.hpp" +#include "filter.hpp" #include diff --git a/groupby.hpp b/groupby.hpp index 1abc2b93..e42b6755 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -1,7 +1,7 @@ #ifndef GROUP__BY__HPP #define GROUP__BY__HPP -#include +#include "iterbase.hpp" #include #include diff --git a/grouper.hpp b/grouper.hpp index b359ba7c..eb885e27 100644 --- a/grouper.hpp +++ b/grouper.hpp @@ -2,6 +2,7 @@ #define GROUPER_HPP #include "iterator_range.hpp" + #include #include #include diff --git a/imap.hpp b/imap.hpp index 0d3424a9..ea447f81 100644 --- a/imap.hpp +++ b/imap.hpp @@ -1,7 +1,7 @@ #ifndef IMAP__H__ #define IMAP__H__ -#include +#include "zip.hpp" #include #include diff --git a/itertools.hpp b/itertools.hpp index b5a87d5d..4129c4c7 100644 --- a/itertools.hpp +++ b/itertools.hpp @@ -1,35 +1,35 @@ #ifndef ITERTOOLS_HPP #define ITERTOOLS_HPP -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "chain.hpp" +#include "combinations.hpp" +#include "combinations_with_replacement.hpp" +#include "compress.hpp" +#include "count.hpp" +#include "cycle.hpp" +#include "dropwhile.hpp" +#include "enumerate.hpp" +#include "filter.hpp" +#include "filterfalse.hpp" +#include "groupby.hpp" +#include "grouper.hpp" +#include "imap.hpp" +#include "iterator_range.hpp" +#include "moving_section.hpp" +#include "permutations.hpp" +#include "powerset.hpp" +#include "product.hpp" +#include "range.hpp" +#include "repeat.hpp" +#include "reverse.hpp" +#include "slice.hpp" +#include "sorted.hpp" +#include "takewhile.hpp" +#include "unique_everseen.hpp" +#include "unique_justseen.hpp" +#include "wrap_iter.hpp" +#include "zip.hpp" +#include "zip_longest.hpp" //not sure if should include "iterator_range.hpp" //since it's already in everything diff --git a/moving_section.hpp b/moving_section.hpp index d4dc52f4..3ee6eb9b 100644 --- a/moving_section.hpp +++ b/moving_section.hpp @@ -2,6 +2,7 @@ #define MOVING_SECTION_HPP #include "iterator_range.hpp" + #include #include #include diff --git a/permutations.hpp b/permutations.hpp index d9a65e2d..1d0e4442 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -2,6 +2,7 @@ #define PERMUTATIONS_HPP #include "iterator_range.hpp" + #include #include #include diff --git a/powerset.hpp b/powerset.hpp index 58e7cdfc..178bd756 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -3,6 +3,7 @@ #include "iterator_range.hpp" #include "combinations.hpp" + #include namespace iter { diff --git a/product.hpp b/product.hpp index 42465b04..e934c362 100644 --- a/product.hpp +++ b/product.hpp @@ -1,9 +1,10 @@ #ifndef PRODUCT_HPP #define PRODUCT_HPP +#include "iterator_range.hpp" + #include #include #include -#include "iterator_range.hpp" namespace iter { template diff --git a/slice.hpp b/slice.hpp index 5f1d289f..b6c84db0 100644 --- a/slice.hpp +++ b/slice.hpp @@ -1,7 +1,7 @@ #ifndef SLICE_HPP #define SLICE_HPP -#include +#include "iterbase.hpp" #include #include diff --git a/sorted.hpp b/sorted.hpp index b9b7a215..1e5cd20c 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -1,7 +1,7 @@ #ifndef SORTED__HPP__ #define SORTED__HPP__ -#include +#include "iterbase.hpp" #include #include diff --git a/takewhile.hpp b/takewhile.hpp index 8531223f..8d2b3088 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -1,7 +1,7 @@ #ifndef TAKEWHILE__H__ #define TAKEWHILE__H__ -#include +#include "iterbase.hpp" #include #include diff --git a/tests/SConstruct b/tests/SConstruct index a28500f5..835050bf 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -3,7 +3,7 @@ import os env = Environment( CXX='c++', - CXXFLAGS= ['-g', '-Wall', '-Wextra', + CXXFLAGS= ['-g', '-Wall', '-Wextra', '-pedantic', '-std=c++11', '-I/usr/local/include'], CPPPATH='..', diff --git a/unique_everseen.hpp b/unique_everseen.hpp index 53250b2d..1a67f7e8 100644 --- a/unique_everseen.hpp +++ b/unique_everseen.hpp @@ -2,6 +2,7 @@ #define UNIQUE_EVERSEEN_HPP #include "filter.hpp" + #include #include #include diff --git a/unique_justseen.hpp b/unique_justseen.hpp index 296c0977..5729ae23 100644 --- a/unique_justseen.hpp +++ b/unique_justseen.hpp @@ -2,6 +2,7 @@ #define UNIQUE_JUSTSEEN_HPP #include "filter.hpp" + #include #include #include diff --git a/zip_longest.hpp b/zip_longest.hpp index 56d67e90..b81b1268 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -1,11 +1,12 @@ #ifndef ZIP_LONGEST_HPP #define ZIP_LONGEST_HPP +#include "iterator_range.hpp" + #include #include #include #include -#include "iterator_range.hpp" namespace iter { template From 0db723c0a13609b1733fce8d282c4505185f7152 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 27 Nov 2013 17:10:39 -0500 Subject: [PATCH 0251/1866] Update README.md --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index b227a8a4..20eee131 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ library. [takewhile](#takewhile)
[dropwhile](#dropwhile)
[cycle](#cycle)
+[groupby](#groupby)
[compress](#compress)
[chain](#chain)
[reverse](#reverse)
@@ -207,6 +208,29 @@ for (auto i : cycle(vec)) { } ``` +groupby +------- +Separate an iterable into groups sharing a common key. The following example +creates a new group whenever a string of a different length is encountered. +```c++ +vector vec = { + "hi", "ab", "ho", + "abc", "def", + "abcde", "efghi" +}; + +for (auto gb : groupby(vec, [] (const string &s) {return s.length(); })) { + cout << "key: " << gb.first << '\n'; + cout << "content: "; + for (auto s : gb.second) { + cout << s << " "; + } + cout << '\n'; +} +``` +*Note*: Just like Python's `itertools.groupby`, this doesn't do any sorting. +It just iterates through, making a new group each time there is a key change. +Thus, the the group is unsorted, the same key may appear multiple times. zip --- From 8eb4a9539d054fd82773c8c6561d9d3ae4d78a71 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 27 Nov 2013 16:14:54 -0500 Subject: [PATCH 0252/1866] Adds groupby test with lambda --- tests/testgroupby.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/testgroupby.cpp b/tests/testgroupby.cpp index c796e215..89aace14 100644 --- a/tests/testgroupby.cpp +++ b/tests/testgroupby.cpp @@ -29,6 +29,15 @@ int main() 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) { From c8b15ef6a428e7f4f0cd187265ef1641a1936104 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 14 Dec 2013 02:32:25 -0500 Subject: [PATCH 0253/1866] Moves range step check to range function Also compresses separate Range constructors into one --- range.hpp | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/range.hpp b/range.hpp index 07aa655f..939487e2 100644 --- a/range.hpp +++ b/range.hpp @@ -22,7 +22,7 @@ namespace iter { // Thrown when step 0 occurs class RangeException : public std::exception { virtual const char *what() const throw() { - return "Range() step argument must not be zero"; + return "Range() step must be non-zero"; } }; @@ -46,11 +46,6 @@ namespace iter { const T start; const T stop; const T step; - void step_check() const throw(RangeException) { - if (step == 0) { - throw RangeException(); - } - } Range(T stop) : start(0), @@ -58,19 +53,11 @@ namespace iter { step(1) { } - Range(T start, T stop) : - start(start), - stop(stop), - step(1) - { } - - Range(T start, T stop, T step) : + Range(T start, T stop, T step=1) : start(start), stop(stop), step(step) - { - this->step_check(); - } + { } public: Range() = delete; @@ -105,12 +92,12 @@ namespace iter { // There are two odd cases that need to be handled // // 1) The Range is infinite, such as - // Range (-1, 0, -1) which would go forever down toward + // Range (-1, 0, -1) which would go forever down toward // infinitely (theoretically). If this occurs, the Range // will instead effectively be empty // // 2) (stop - start) % step != 0. For - // example Range(1, 10, 2). The iterator will never be + // example Range(1, 10, 2). The iterator will never be // exactly equal to the stop value. bool operator!=(const Range::Iterator & other) const { return !(this->step > 0 && this->value >= other.value) @@ -118,7 +105,6 @@ namespace iter { } }; - Iterator begin() const { return Iterator(start, step); } @@ -129,7 +115,6 @@ namespace iter { }; - template Range range(T stop) { return Range(stop); @@ -142,6 +127,9 @@ namespace iter { template Range range(T start, T stop, T step) { + if (step == 0) { + throw RangeException(); + } return Range(start, stop, step); } } From bf417cccb6c168556e2f95a6388a4e1130bf9323 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 14 Dec 2013 02:37:11 -0500 Subject: [PATCH 0254/1866] fixes unever indents --- tests/SConstruct | 60 ++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/tests/SConstruct b/tests/SConstruct index 835050bf..56b5aa44 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -12,36 +12,36 @@ env = Environment( # allows highighting to print to terminal from compiler output env['ENV']['TERM'] = os.environ['TERM'] -progs = Split( ''' - cycle - enumerate - range - zip - slice - reverse - filter - repeat - takewhile - dropwhile - zip_longest - product - permutations - compress - combinations_with_replacement - combinations - powerset - moving_section - imap - count - filterfalse - grouper - chain - command_chains - groupby - sorted - unique_justseen - unique_everseen - ''') +progs = Split(''' + cycle + enumerate + range + zip + slice + reverse + filter + repeat + takewhile + dropwhile + zip_longest + product + permutations + compress + combinations_with_replacement + combinations + powerset + moving_section + imap + count + filterfalse + grouper + chain + command_chains + groupby + sorted + unique_justseen + unique_everseen + ''') for p in progs: From 16f26c548fe821f429f5297c3ce19d48fc9d70f9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 28 Dec 2013 21:13:29 -0500 Subject: [PATCH 0255/1866] Removes cycle's requirement on iterator assignment Previously the iterator of the iterable being cycled over needed to support assignment for when the end was reached. This shortcoming was exposed when cycling over a range, whose iterator has a const step data member, and hence cannot be assigned with operator=. Instead, the destructor is explicitly invoked and the iterator is reconstructed using placement new. --- cycle.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cycle.hpp b/cycle.hpp index 53da8619..cc120ac1 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -63,7 +63,9 @@ namespace iter { ++this->sub_iter; // reset to beginning upon reaching the end if (!(this->sub_iter != this->end)) { - this->sub_iter = this->begin; + this->sub_iter.~contained_iter_type(); + new(&this->sub_iter) contained_iter_type( + this->begin); } return *this; } From 48b264bce7694a7939ba4edc6c04401d00434b89 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 28 Dec 2013 21:20:48 -0500 Subject: [PATCH 0256/1866] Removes operator= from range iterator --- range.hpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/range.hpp b/range.hpp index 939487e2..02d9944b 100644 --- a/range.hpp +++ b/range.hpp @@ -72,11 +72,6 @@ namespace iter { step(step) { } - Iterator & operator=(const Iterator &other) { - this->value = other.value; - return *this; - } - T operator*() const { return this->value; } From 8401812c445ad8dd5d7c8cfcd364ca31fd165160 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 28 Dec 2013 21:37:07 -0500 Subject: [PATCH 0257/1866] Adds comment --- cycle.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cycle.hpp b/cycle.hpp index cc120ac1..bb2b7abe 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -63,6 +63,8 @@ namespace iter { ++this->sub_iter; // reset to beginning upon reaching the end if (!(this->sub_iter != this->end)) { + // explicit destruction with placement new in order + // to support iterators with no operator= this->sub_iter.~contained_iter_type(); new(&this->sub_iter) contained_iter_type( this->begin); From e0f1c34d483ef095039fb40386b6cea944b8b3b2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 28 Dec 2013 21:37:20 -0500 Subject: [PATCH 0258/1866] Removes requirement on iterator having operator= --- takewhile.hpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/takewhile.hpp b/takewhile.hpp index 8d2b3088..3670cff2 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -55,11 +55,15 @@ namespace iter { const contained_iter_type sub_end; FilterFunc filter_func; - // increment until the iterator points to is true on the - // predicate. Called by constructor and operator++ + // check if the current value is true under the predicate + // if it is not, set the sub_iter to the end using + // placement new to avoid the requirement of the iterator + // having an operator= void check_current() { if (!this->filter_func(*this->sub_iter)) { - this->sub_iter = this->sub_end; + this->sub_iter.~contained_iter_type(); + new(&this->sub_iter) contained_iter_type( + this->sub_end); } } From aff5621ab2b5f36142bd27ae2cdf292e8c8aafac Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 28 Dec 2013 21:50:25 -0500 Subject: [PATCH 0259/1866] Fixes memory error in takewhile check_current was being called in the constructor on each Iterator creation, thus when an end iterator was created, the end was being checked against the predicate which was one passed the end. The fix checks for end before doing the check in the constructor. --- takewhile.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/takewhile.hpp b/takewhile.hpp index 3670cff2..58ca4bd3 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -75,7 +75,10 @@ namespace iter { sub_end(end), filter_func(filter_func) { - this->check_current(); + if (this->sub_iter != this->sub_end) { + // only do the check if not already at the end + this->check_current(); + } } contained_iter_ret operator*() const { From 428dce969db8dc454339b530fd82e773846b17ec Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 8 Jan 2014 16:07:29 -0500 Subject: [PATCH 0260/1866] replaces throw() with noexcept --- range.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/range.hpp b/range.hpp index 02d9944b..175f3bac 100644 --- a/range.hpp +++ b/range.hpp @@ -21,8 +21,8 @@ namespace iter { // Thrown when step 0 occurs class RangeException : public std::exception { - virtual const char *what() const throw() { - return "Range() step must be non-zero"; + virtual const char *what() const noexcept { + return "range step must be non-zero"; } }; From 51b126693fada8a4118fd9cf7eb2972b30beb6d3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 8 Jan 2014 16:08:28 -0500 Subject: [PATCH 0261/1866] attempts to flatten enumerate --- enumerate.hpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 12bf9af8..5868c92b 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -32,7 +32,7 @@ namespace iter { Enumerable enumerate(Container &&); template - class Enumerable : public IterBase{ + class Enumerable { private: Container & container; @@ -43,9 +43,7 @@ namespace iter { friend Enumerable> enumerate( std::initializer_list &&); - using typename IterBase::contained_iter_type; - - using typename IterBase::contained_iter_ret; + using IterDef = IterBase; Enumerable(Container && container) : container(container) { } @@ -61,8 +59,8 @@ namespace iter { class IterYield { public: std::size_t index; - contained_iter_ret element; - IterYield(std::size_t i, contained_iter_ret elem) : + typename IterDef::contained_iter_ret element; + IterYield(std::size_t i, typename IterDef::contained_iter_ret elem): index(i), element(elem) { } @@ -73,10 +71,10 @@ namespace iter { // Each dereference returns an IterYield. class Iterator { private: - contained_iter_type sub_iter; + typename IterDef::contained_iter_type sub_iter; std::size_t index; public: - Iterator (contained_iter_type si) : + Iterator (typename IterDef::contained_iter_type si) : sub_iter(si), index(0) { } From 4d797e34e8b7b42d97d2c394ba6a7fbe916933e2 Mon Sep 17 00:00:00 2001 From: Ben Jones Date: Wed, 8 Jan 2014 15:34:17 -0700 Subject: [PATCH 0262/1866] added specialization of range w/ unsigned types --- range.hpp | 15 +++++++++++---- tests/testrange.cpp | 25 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/range.hpp b/range.hpp index 175f3bac..15e27ec8 100644 --- a/range.hpp +++ b/range.hpp @@ -94,10 +94,17 @@ namespace iter { // 2) (stop - start) % step != 0. For // example Range(1, 10, 2). The iterator will never be // exactly equal to the stop value. - bool operator!=(const Range::Iterator & other) const { - return !(this->step > 0 && this->value >= other.value) - && !(this->step < 0 && this->value <= other.value); - } + bool operator!=(const Range::Iterator & other) const { + return not_equal_to(other, typename std::is_unsigned::type()); + } + private: + bool not_equal_to(const Range::Iterator& other, std::true_type /*unsigned*/) const{ + return this->value < other.value; + } + bool not_equal_to(const Range::Iterator& other, std::false_type /*signed*/) const{ + return !(this->step > 0 && this->value >= other.value) + && !(this->step < 0 && this->value <= other.value); + } }; Iterator begin() const { diff --git a/tests/testrange.cpp b/tests/testrange.cpp index fd7a294f..9404ae57 100644 --- a/tests/testrange.cpp +++ b/tests/testrange.cpp @@ -38,6 +38,31 @@ int main() 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"; From b88e7e5749fcfea0295e90854f1592701cc29799 Mon Sep 17 00:00:00 2001 From: Ben Jones Date: Sat, 11 Jan 2014 18:15:19 -0700 Subject: [PATCH 0263/1866] added include for type_traits --- range.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/range.hpp b/range.hpp index 15e27ec8..c570ad34 100644 --- a/range.hpp +++ b/range.hpp @@ -16,6 +16,7 @@ // If a step of 0 is provided, a RangeException will be thrown #include +#include namespace iter { From b53cd56724059fa392083fa2f0ab1d0fd58ba634 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 12 Jan 2014 12:06:38 -0500 Subject: [PATCH 0264/1866] Formatting --- range.hpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/range.hpp b/range.hpp index c570ad34..70b57966 100644 --- a/range.hpp +++ b/range.hpp @@ -67,6 +67,14 @@ namespace iter { private: T value; const T step; + + bool not_equal_to(const Range::Iterator& other, std::true_type /*unsigned*/) const{ + return this->value < other.value; + } + bool not_equal_to(const Range::Iterator& other, std::false_type /*signed*/) const{ + return !(this->step > 0 && this->value >= other.value) + && !(this->step < 0 && this->value <= other.value); + } public: Iterator(T val, T step) : value(val), @@ -96,16 +104,8 @@ namespace iter { // example Range(1, 10, 2). The iterator will never be // exactly equal to the stop value. bool operator!=(const Range::Iterator & other) const { - return not_equal_to(other, typename std::is_unsigned::type()); - } - private: - bool not_equal_to(const Range::Iterator& other, std::true_type /*unsigned*/) const{ - return this->value < other.value; - } - bool not_equal_to(const Range::Iterator& other, std::false_type /*signed*/) const{ - return !(this->step > 0 && this->value >= other.value) - && !(this->step < 0 && this->value <= other.value); - } + return not_equal_to(other, typename std::is_unsigned::type()); + } }; Iterator begin() const { From ff3b45be5de3ad5691e2f09ff8132030007643a4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 12 Jan 2014 12:07:04 -0500 Subject: [PATCH 0265/1866] removes leading underscores from include guard --- range.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/range.hpp b/range.hpp index 70b57966..62ec6362 100644 --- a/range.hpp +++ b/range.hpp @@ -1,5 +1,5 @@ -#ifndef __RANGE__H__ -#define __RANGE__H__ +#ifndef RANGE__H__ +#define RANGE__H__ // range() for range-based loops with start, stop, and step. // @@ -137,4 +137,4 @@ namespace iter { } } -#endif //ifndef __RANGE__H__ +#endif //ifndef RANGE__H__ From 789458e34c0d53dc27f666c52b0a890b18209504 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 12 Jan 2014 12:16:26 -0500 Subject: [PATCH 0266/1866] flattens with explicit using --- enumerate.hpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 5868c92b..84a9a1cb 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -43,7 +43,10 @@ namespace iter { friend Enumerable> enumerate( std::initializer_list &&); - using IterDef = IterBase; + using contained_iter_ret = + typename IterBase::contained_iter_ret; + using contained_iter_type = + typename IterBase::contained_iter_type; Enumerable(Container && container) : container(container) { } @@ -59,8 +62,8 @@ namespace iter { class IterYield { public: std::size_t index; - typename IterDef::contained_iter_ret element; - IterYield(std::size_t i, typename IterDef::contained_iter_ret elem): + contained_iter_ret element; + IterYield(std::size_t i, contained_iter_ret elem): index(i), element(elem) { } @@ -71,10 +74,10 @@ namespace iter { // Each dereference returns an IterYield. class Iterator { private: - typename IterDef::contained_iter_type sub_iter; + contained_iter_type sub_iter; std::size_t index; public: - Iterator (typename IterDef::contained_iter_type si) : + Iterator (contained_iter_type si) : sub_iter(si), index(0) { } From f55c4be1b64c4a8ae7249ef70b1ea4c963b27c0f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 12 Jan 2014 14:27:22 -0500 Subject: [PATCH 0267/1866] Removes IterBase in favor of templated usings --- iterbase.hpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/iterbase.hpp b/iterbase.hpp index 55936753..a0429cbd 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -1,26 +1,26 @@ #ifndef ITERBASE__HPP__ #define ITERBASE__HPP__ + +// This file consists of utilities used for the generic nature of the +// iterable wrapper classes. As such, the contents of this file should be +// considered UNDOCUMENTED and is subject to change without warning. This +// also applies to the name of the file + #include #include namespace iter { - template - class IterBase{ - public: - // Type of the Container::Iterator, but since the name of that - // iterator can be anything, we have to grab it with this - using contained_iter_type = - decltype(std::begin(std::declval())); + // iterator_type is the type of C's iterator + template + using iterator_type = + decltype(std::begin(std::declval())); - // The type returned when dereferencing the Container::Iterator - using contained_iter_ret = - decltype(*std::declval()); - - IterBase() = default; - IterBase(const IterBase &) = default; - IterBase & operator=(const IterBase &) = delete; - }; + // iterator_deref is the type obtained by dereferencing an iterator + // to an object of type C + template + using iterator_deref = + decltype(*std::declval&>()); } #endif // #ifndef ITERBASE__HPP__ From 97e9825223501340816c16fb0debdbcee299efc8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 12 Jan 2014 14:47:48 -0500 Subject: [PATCH 0268/1866] compress uses new type aliases --- compress.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compress.hpp b/compress.hpp index b97db516..11cb1720 100644 --- a/compress.hpp +++ b/compress.hpp @@ -28,7 +28,7 @@ namespace iter { std::initializer_list &&, std::initializer_list &&); template - class Compressed : public IterBase { + class Compressed { private: Container & container; Selector & selectors; @@ -50,9 +50,9 @@ namespace iter { friend Compressed, std::initializer_list> compress( std::initializer_list &&, std::initializer_list &&); - using typename IterBase::contained_iter_type; + - using typename IterBase::contained_iter_ret; + // Selector::Iterator type using selector_iter_type = decltype(std::begin(selectors)); @@ -70,8 +70,8 @@ namespace iter { class Iterator { private: - contained_iter_type sub_iter; - const contained_iter_type sub_end; + iterator_type sub_iter; + const iterator_type sub_end; selector_iter_type selector_iter; const selector_iter_type selector_end; @@ -90,8 +90,8 @@ namespace iter { } public: - Iterator (contained_iter_type cont_iter, - contained_iter_type cont_end, + Iterator (iterator_type cont_iter, + iterator_type cont_end, selector_iter_type sel_iter, selector_iter_type sel_end) : sub_iter(cont_iter), @@ -102,7 +102,7 @@ namespace iter { this->skip_failures(); } - contained_iter_ret operator*() const { + iterator_deref operator*() const { return *this->sub_iter; } From 0c51a4415df3ac99ab0401e7845d22cd719258ee Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 12 Jan 2014 14:47:58 -0500 Subject: [PATCH 0269/1866] cycle uses new type aliases --- cycle.hpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/cycle.hpp b/cycle.hpp index bb2b7abe..20be700b 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -21,7 +21,7 @@ namespace iter { std::initializer_list &&); template - class Cycle : public IterBase{ + class Cycle { private: // The cycle function is the only thing allowed to create a Cycle friend Cycle cycle(Container &&); @@ -29,9 +29,9 @@ namespace iter { friend Cycle> cycle( std::initializer_list &&); - using typename IterBase::contained_iter_type; + - using typename IterBase::contained_iter_ret; + Container & container; @@ -44,18 +44,19 @@ namespace iter { Cycle(const Cycle &) = default; class Iterator { private: - contained_iter_type sub_iter; - const contained_iter_type begin; - const contained_iter_type end; + using iter_type = iterator_type; + iterator_type sub_iter; + const iterator_type begin; + const iterator_type end; public: - Iterator (contained_iter_type iter, - contained_iter_type end) : + Iterator (iterator_type iter, + iterator_type end) : sub_iter(iter), begin(iter), end(end) { } - contained_iter_ret operator*() const { + iterator_deref operator*() const { return *this->sub_iter; } @@ -65,8 +66,8 @@ namespace iter { if (!(this->sub_iter != this->end)) { // explicit destruction with placement new in order // to support iterators with no operator= - this->sub_iter.~contained_iter_type(); - new(&this->sub_iter) contained_iter_type( + this->sub_iter.~iter_type(); + new(&this->sub_iter) iterator_type( this->begin); } return *this; From 020c86056f6051f39a27a091df48175bba942247 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 12 Jan 2014 14:48:20 -0500 Subject: [PATCH 0270/1866] dropwhile uses new type aliases --- dropwhile.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index 1f13efc9..626ac733 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -21,7 +21,7 @@ namespace iter { FilterFunc, std::initializer_list &&); template - class DropWhile : IterBase { + class DropWhile { private: Container & container; FilterFunc filter_func; @@ -33,9 +33,9 @@ namespace iter { friend DropWhile> dropwhile( FF, std::initializer_list &&); - using typename IterBase::contained_iter_type; + - using typename IterBase::contained_iter_ret; + // Value constructor for use only in the dropwhile function @@ -50,8 +50,8 @@ namespace iter { DropWhile(const DropWhile &) = default; class Iterator { private: - contained_iter_type sub_iter; - const contained_iter_type sub_end; + iterator_type sub_iter; + const iterator_type sub_end; FilterFunc filter_func; // skip all values for which the predicate is true @@ -63,8 +63,8 @@ namespace iter { } public: - Iterator (contained_iter_type iter, - contained_iter_type end, + Iterator (iterator_type iter, + iterator_type end, FilterFunc filter_func) : sub_iter(iter), sub_end(end), @@ -73,7 +73,7 @@ namespace iter { this->skip_passes(); } - contained_iter_ret operator*() const { + iterator_deref operator*() const { return *this->sub_iter; } From f0f6378f234bb3b97bfb4628657362ac1961b403 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 12 Jan 2014 14:48:28 -0500 Subject: [PATCH 0271/1866] enumerate uses new type aliases --- enumerate.hpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 84a9a1cb..2bb5f806 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -43,11 +43,6 @@ namespace iter { friend Enumerable> enumerate( std::initializer_list &&); - using contained_iter_ret = - typename IterBase::contained_iter_ret; - using contained_iter_type = - typename IterBase::contained_iter_type; - Enumerable(Container && container) : container(container) { } public: @@ -62,8 +57,8 @@ namespace iter { class IterYield { public: std::size_t index; - contained_iter_ret element; - IterYield(std::size_t i, contained_iter_ret elem): + iterator_deref element; + IterYield(std::size_t i, iterator_deref elem): index(i), element(elem) { } @@ -74,10 +69,10 @@ namespace iter { // Each dereference returns an IterYield. class Iterator { private: - contained_iter_type sub_iter; + iterator_type sub_iter; std::size_t index; public: - Iterator (contained_iter_type si) : + Iterator (iterator_type si) : sub_iter(si), index(0) { } From 86e8753705020e41f5aecb5f07f7ed2215dad108 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 12 Jan 2014 14:48:37 -0500 Subject: [PATCH 0272/1866] filter uses new type aliases --- filter.hpp | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/filter.hpp b/filter.hpp index 3e51d2d9..2decb950 100644 --- a/filter.hpp +++ b/filter.hpp @@ -21,7 +21,7 @@ namespace iter { FilterFunc, std::initializer_list &&); template - class Filter : IterBase{ + class Filter { private: Container & container; FilterFunc filter_func; @@ -33,9 +33,9 @@ namespace iter { template friend Filter> filter( FF, std::initializer_list &&); - using typename IterBase::contained_iter_type; + - using typename IterBase::contained_iter_ret; + // Value constructor for use only in the filter function Filter(FilterFunc filter_func, Container && container) : @@ -50,8 +50,8 @@ namespace iter { class Iterator { protected: - contained_iter_type sub_iter; - const contained_iter_type sub_end; + iterator_type sub_iter; + const iterator_type sub_end; FilterFunc filter_func; // increment until the iterator points to is true on the @@ -64,8 +64,8 @@ namespace iter { } public: - Iterator (contained_iter_type iter, - contained_iter_type end, + Iterator (iterator_type iter, + iterator_type end, FilterFunc filter_func) : sub_iter(iter), sub_end(end), @@ -74,7 +74,7 @@ namespace iter { this->skip_failures(); } - contained_iter_ret operator*() const { + iterator_deref operator*() const { return *this->sub_iter; } @@ -131,12 +131,8 @@ namespace iter { template class BoolTester { - protected: - using contained_iter_ret = - typename IterBase::contained_iter_ret; - public: - bool operator() (const contained_iter_ret item) const { + bool operator() (const iterator_deref item) const { return bool(item); } }; From 63c1f8d44a859d3f610787fbaaa1ef1f884b76e1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 12 Jan 2014 14:48:49 -0500 Subject: [PATCH 0273/1866] filterfalse uses new type aliases --- filterfalse.hpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/filterfalse.hpp b/filterfalse.hpp index 02c3b9b7..dfd2716c 100644 --- a/filterfalse.hpp +++ b/filterfalse.hpp @@ -17,9 +17,6 @@ namespace iter { private: FilterFunc filter_func; - using contained_iter_ret = - typename IterBase::contained_iter_ret; - public: PredicateFlipper(FilterFunc filter_func) : filter_func(filter_func) @@ -29,7 +26,7 @@ namespace iter { PredicateFlipper(const PredicateFlipper &) = default; // Calls the filter_func - bool operator() (const contained_iter_ret item) const { + bool operator() (const iterator_deref item) const { return !bool(filter_func(item)); } }; @@ -37,13 +34,9 @@ namespace iter { // Reverses the bool() conversion result of anything that supports a // bool conversion template - class BoolFlipper : public BoolTester { - private: - using contained_iter_ret = - typename BoolTester::contained_iter_ret; - + class BoolFlipper { public: - bool operator() (const contained_iter_ret item) const { + bool operator() (const iterator_deref item) const { return !bool(item); } }; From 5e323d44dd62a176affa5a10845b32c8c8983222 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 12 Jan 2014 14:49:05 -0500 Subject: [PATCH 0274/1866] groupby uses new type aliases --- groupby.hpp | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index e42b6755..ed6fe0d0 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -20,7 +20,7 @@ namespace iter { std::initializer_list &&, KeyFunc); template - class GroupBy : IterBase { + class GroupBy { private: Container & container; KeyFunc key_func; @@ -31,13 +31,13 @@ namespace iter { friend GroupBy, KF> groupby( std::initializer_list &&, KF); - using typename IterBase::contained_iter_type; + - using typename IterBase::contained_iter_ret; + using key_func_ret = decltype(std::declval()( - std::declval())); + std::declval>())); GroupBy(Container && container, KeyFunc key_func) : container(container), @@ -57,17 +57,17 @@ namespace iter { class Iterator { private: - contained_iter_type sub_iter; - contained_iter_type sub_iter_peek; - const contained_iter_type sub_end; + iterator_type sub_iter; + iterator_type sub_iter_peek; + const iterator_type sub_end; KeyFunc key_func; using KeyGroupPair = std::pair; public: - Iterator (contained_iter_type si, - contained_iter_type end, + Iterator (iterator_type si, + iterator_type end, KeyFunc key_func) : sub_iter(si), sub_end(end), @@ -100,7 +100,7 @@ namespace iter { return this->sub_iter == this->sub_end; } - contained_iter_ret current() const { + iterator_deref current() const { return *this->sub_iter; } @@ -188,7 +188,7 @@ namespace iter { return *this; } - contained_iter_ret operator*() const { + iterator_deref operator*() const { return this->group.owner.current(); } }; @@ -224,12 +224,10 @@ namespace iter { // items in the sequence directly template class ItemReturner { - private: - using contained_iter_ret = - typename IterBase::contained_iter_ret; public: ItemReturner() = default; - contained_iter_ret operator() (contained_iter_ret item) const { + iterator_deref operator() ( + iterator_deref item) const { return item; } }; From b504566e11bcab2d7e312fdbb2acfdbb21b36859 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 12 Jan 2014 14:49:22 -0500 Subject: [PATCH 0275/1866] slice uses new type aliases --- slice.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/slice.hpp b/slice.hpp index b6c84db0..2415225e 100644 --- a/slice.hpp +++ b/slice.hpp @@ -52,7 +52,7 @@ namespace iter { template - class Slice : public IterBase{ + class Slice { private: Container & container; DifferenceType start; @@ -65,9 +65,9 @@ namespace iter { //template //friend Slice> slice(std::initializer_list &&); - using typename IterBase::contained_iter_type; + - using typename IterBase::contained_iter_ret; + public: @@ -99,13 +99,13 @@ namespace iter { class Iterator { private: - contained_iter_type sub_iter; + iterator_type sub_iter; DifferenceType current; const DifferenceType stop; const DifferenceType step; public: - Iterator (contained_iter_type si, DifferenceType start, + Iterator (iterator_type si, DifferenceType start, DifferenceType stop, DifferenceType step) : sub_iter(si), current(start), @@ -113,7 +113,7 @@ namespace iter { step(step) { } - contained_iter_ret operator*() const { + iterator_deref operator*() const { return *this->sub_iter; } From 8081dd37532535a5043e141c192a5979bb1e33e8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 12 Jan 2014 14:49:30 -0500 Subject: [PATCH 0276/1866] sorted uses new type aliases --- sorted.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sorted.hpp b/sorted.hpp index 1e5cd20c..6a0c518a 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -15,16 +15,16 @@ namespace iter { Sorted sorted(Container &, CompareFunc); template - class Sorted : IterBase { + class Sorted { private: friend Sorted sorted(Container &, CompareFunc); - using typename IterBase::contained_iter_type; + - using typename IterBase::contained_iter_ret; + - std::vector sorted_iters; + std::vector> sorted_iters; using sorted_iter_type = decltype(std::begin(sorted_iters)); @@ -42,8 +42,8 @@ namespace iter { // sort by comparing the elements that the iterators point to std::sort(std::begin(sorted_iters), std::end(sorted_iters), - [&] (const contained_iter_type & it1, - const contained_iter_type & it2) + [&] (const iterator_type & it1, + const iterator_type & it2) { return compare_func(*it1, *it2); }); } @@ -61,7 +61,7 @@ namespace iter { IteratorIterator(const IteratorIterator &) = default; // Dereference the current iterator before returning - contained_iter_ret operator*() { + iterator_deref operator*() { return *sorted_iter_type::operator*(); } }; From 5b34bcae027b783136f72513fed084cf24baaf9a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 12 Jan 2014 14:49:42 -0500 Subject: [PATCH 0277/1866] takewhile uses new type aliases --- takewhile.hpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/takewhile.hpp b/takewhile.hpp index 58ca4bd3..caf135d3 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -21,7 +21,7 @@ namespace iter { FilterFunc, std::initializer_list &&); template - class TakeWhile : IterBase{ + class TakeWhile { private: Container & container; FilterFunc filter_func; @@ -33,9 +33,9 @@ namespace iter { friend TakeWhile> takewhile( FF, std::initializer_list &&); - using typename IterBase::contained_iter_type; + - using typename IterBase::contained_iter_ret; + // Value constructor for use only in the takewhile function TakeWhile(FilterFunc filter_func, Container && container) : @@ -51,8 +51,9 @@ namespace iter { class Iterator { private: - contained_iter_type sub_iter; - const contained_iter_type sub_end; + using iter_type = iterator_type; + iterator_type sub_iter; + const iterator_type sub_end; FilterFunc filter_func; // check if the current value is true under the predicate @@ -61,15 +62,15 @@ namespace iter { // having an operator= void check_current() { if (!this->filter_func(*this->sub_iter)) { - this->sub_iter.~contained_iter_type(); - new(&this->sub_iter) contained_iter_type( + this->sub_iter.~iter_type(); + new(&this->sub_iter) iterator_type( this->sub_end); } } public: - Iterator (contained_iter_type iter, - contained_iter_type end, + Iterator (iterator_type iter, + iterator_type end, FilterFunc filter_func) : sub_iter(iter), sub_end(end), @@ -81,7 +82,7 @@ namespace iter { } } - contained_iter_ret operator*() const { + iterator_deref operator*() const { return *this->sub_iter; } From 60936e99c381d9b82c89f7d447f2e367f1fb7548 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 12 Jan 2014 14:50:01 -0500 Subject: [PATCH 0278/1866] comments expanded --- iterbase.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iterbase.hpp b/iterbase.hpp index a0429cbd..84fa8c32 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -5,7 +5,8 @@ // This file consists of utilities used for the generic nature of the // iterable wrapper classes. As such, the contents of this file should be // considered UNDOCUMENTED and is subject to change without warning. This -// also applies to the name of the file +// also applies to the name of the file. No user code should include +// this file directly. #include #include From 0e25b272a4ef767f801ec8cbd99b2807fc394409 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 12 Jan 2014 15:07:54 -0500 Subject: [PATCH 0279/1866] removes extra qualifiers --- range.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/range.hpp b/range.hpp index 62ec6362..5aac5e61 100644 --- a/range.hpp +++ b/range.hpp @@ -68,10 +68,10 @@ namespace iter { T value; const T step; - bool not_equal_to(const Range::Iterator& other, std::true_type /*unsigned*/) const{ + bool not_equal_to(const Iterator& other, std::true_type /*unsigned*/) const{ return this->value < other.value; } - bool not_equal_to(const Range::Iterator& other, std::false_type /*signed*/) const{ + bool not_equal_to(const Iterator& other, std::false_type /*signed*/) const{ return !(this->step > 0 && this->value >= other.value) && !(this->step < 0 && this->value <= other.value); } @@ -103,7 +103,7 @@ namespace iter { // 2) (stop - start) % step != 0. For // example Range(1, 10, 2). The iterator will never be // exactly equal to the stop value. - bool operator!=(const Range::Iterator & other) const { + bool operator!=(const Iterator & other) const { return not_equal_to(other, typename std::is_unsigned::type()); } }; From a073bac42feeb63d117ae2b63c4f381cc5ee9e26 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 12 Jan 2014 15:09:49 -0500 Subject: [PATCH 0280/1866] formatting in range.hpp --- range.hpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/range.hpp b/range.hpp index 5aac5e61..c82dffa6 100644 --- a/range.hpp +++ b/range.hpp @@ -68,10 +68,15 @@ namespace iter { T value; const T step; - bool not_equal_to(const Iterator& other, std::true_type /*unsigned*/) const{ + // compare unsigned values + bool not_equal_to( + const Iterator& other, std::true_type ) const { return this->value < other.value; } - bool not_equal_to(const Iterator& other, std::false_type /*signed*/) const{ + + // compare signed values + bool not_equal_to( + const Iterator& other, std::false_type) const { return !(this->step > 0 && this->value >= other.value) && !(this->step < 0 && this->value <= other.value); } @@ -104,7 +109,8 @@ namespace iter { // example Range(1, 10, 2). The iterator will never be // exactly equal to the stop value. bool operator!=(const Iterator & other) const { - return not_equal_to(other, typename std::is_unsigned::type()); + return not_equal_to( + other, typename std::is_unsigned::type()); } }; From 569e6a63c21de55ac950aa7a26a65a743e9f5528 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 24 Jan 2014 02:54:08 -0500 Subject: [PATCH 0281/1866] Updates to use uniform initialization --- enumerate.hpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 2bb5f806..9ac24737 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -43,7 +43,7 @@ namespace iter { friend Enumerable> enumerate( std::initializer_list &&); - Enumerable(Container && container) : container(container) { } + Enumerable(Container && container) : container{container} { } public: // Value constructor for use only in the enumerate function @@ -58,9 +58,9 @@ namespace iter { public: std::size_t index; iterator_deref element; - IterYield(std::size_t i, iterator_deref elem): - index(i), - element(elem) + IterYield(std::size_t i, iterator_deref elem) + : index{i}, + element{elem} { } }; @@ -72,9 +72,10 @@ namespace iter { iterator_type sub_iter; std::size_t index; public: - Iterator (iterator_type si) : - sub_iter(si), - index(0) { } + Iterator (iterator_type si) + : sub_iter{si}, + index{0} + { } IterYield operator*() const { return IterYield(this->index, *this->sub_iter); @@ -104,13 +105,14 @@ namespace iter { // Helper function to instantiate an Enumerable template Enumerable enumerate(Container && container) { - return Enumerable(std::forward(container)); + return {std::forward(container)}; } template - Enumerable> enumerate(std::initializer_list && il) + Enumerable> enumerate( + std::initializer_list && il) { - return Enumerable>(std::move(il)); + return {std::move(il)}; } } From ddfe6ad010688e447c20705957e25cad971d9c8b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 24 Jan 2014 03:05:33 -0500 Subject: [PATCH 0282/1866] more brace updates --- enumerate.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 9ac24737..7cb61263 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -93,11 +93,11 @@ namespace iter { }; Iterator begin() const { - return Iterator(std::begin(this->container)); + return {std::begin(this->container)}; } Iterator end() const { - return Iterator(std::end(this->container)); + return {std::end(this->container)}; } }; From 1d27f39f835c0ac03777e83a71f0565612740ea3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 24 Jan 2014 03:06:34 -0500 Subject: [PATCH 0283/1866] uniform initialization updates --- range.hpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/range.hpp b/range.hpp index c82dffa6..28d3e6a7 100644 --- a/range.hpp +++ b/range.hpp @@ -48,16 +48,16 @@ namespace iter { const T stop; const T step; - Range(T stop) : - start(0), - stop(stop), - step(1) + Range(T stop) + : start{0}, + stop{stop}, + step{1} { } - Range(T start, T stop, T step=1) : - start(start), - stop(stop), - step(step) + Range(T start, T stop, T step =1) + : start{start}, + stop{stop}, + step{step} { } public: @@ -81,9 +81,9 @@ namespace iter { && !(this->step < 0 && this->value <= other.value); } public: - Iterator(T val, T step) : - value(val), - step(step) + Iterator(T val, T step) + : value{val}, + step{step} { } T operator*() const { @@ -115,23 +115,23 @@ namespace iter { }; Iterator begin() const { - return Iterator(start, step); + return {start, step}; } Iterator end() const { - return Iterator(stop, step); + return {stop, step}; } }; template Range range(T stop) { - return Range(stop); + return {stop}; } template Range range(T start, T stop) { - return Range(start, stop); + return {start, stop}; } template @@ -139,7 +139,7 @@ namespace iter { if (step == 0) { throw RangeException(); } - return Range(start, stop, step); + return {start, stop, step}; } } From 0113564b8bcb2db57d965fed8564684951921c37 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 24 Jan 2014 03:11:33 -0500 Subject: [PATCH 0284/1866] uniform initialization updates --- compress.hpp | 49 ++++++++++++++++++++----------------------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/compress.hpp b/compress.hpp index 11cb1720..376f432a 100644 --- a/compress.hpp +++ b/compress.hpp @@ -51,16 +51,13 @@ namespace iter { std::initializer_list &&, std::initializer_list &&); - - - // Selector::Iterator type using selector_iter_type = decltype(std::begin(selectors)); // Value constructor for use only in the compress function - Compressed(Container && container, Selector && selectors) : - container(container), - selectors(selectors) + Compressed(Container && container, Selector && selectors) + : container{container}, + selectors{selectors} { } Compressed () = delete; Compressed & operator=(const Compressed &) = delete; @@ -93,11 +90,11 @@ namespace iter { Iterator (iterator_type cont_iter, iterator_type cont_end, selector_iter_type sel_iter, - selector_iter_type sel_end) : - sub_iter(cont_iter), - sub_end(cont_end), - selector_iter(sel_iter), - selector_end(sel_end) + selector_iter_type sel_end) + : sub_iter{cont_iter}, + sub_end{cont_end}, + selector_iter{sel_iter}, + selector_end{sel_end} { this->skip_failures(); } @@ -119,15 +116,13 @@ namespace iter { }; Iterator begin() const { - return Iterator( - std::begin(this->container), std::end(this->container), - std::begin(this->selectors), std::end(this->selectors)); + return {std::begin(this->container), std::end(this->container), + std::begin(this->selectors), std::end(this->selectors)}; } Iterator end() const { - return Iterator( - std::end(this->container), std::end(this->container), - std::end(this->selectors), std::end(this->selectors)); + return {std::end(this->container), std::end(this->container), + std::end(this->selectors), std::end(this->selectors)}; } }; @@ -136,34 +131,30 @@ namespace iter { template Compressed compress( Container && container, Selector && selectors) { - return Compressed( - std::forward(container), - std::forward(selectors)); + return {std::forward(container), + std::forward(selectors)}; } template Compressed, Selector> compress( std::initializer_list && data, Selector && selectors) { - return Compressed, Selector>( - std::move(data), - std::forward(selectors)); + return {std::move(data), + std::forward(selectors)}; } template Compressed> compress( Container && container, std::initializer_list && selectors) { - return Compressed>( - std::forward(container), - std::move(selectors)); + return {std::forward(container), + std::move(selectors)}; } template Compressed, std::initializer_list> compress( std::initializer_list && data, std::initializer_list && selectors) { - return Compressed, std::initializer_list>( - std::move(data), - std::move(selectors)); + return {std::move(data), + std::move(selectors)}; } } From e2d85cd64aea225427414dae0d952b8ac8f77179 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 24 Jan 2014 03:13:38 -0500 Subject: [PATCH 0285/1866] replaces typedef with using --- count.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/count.hpp b/count.hpp index 15119e8b..4945d88f 100644 --- a/count.hpp +++ b/count.hpp @@ -7,9 +7,7 @@ namespace iter { - namespace { - typedef long DefaultRangeType; - } + using DefaultRangeType = long; Range count() { return range(DefaultRangeType(0), From ec69f569dc4d0d9c9bbcbd1c4c88653cc52dcd5c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 24 Jan 2014 03:20:13 -0500 Subject: [PATCH 0286/1866] replaces typedef with using --- cycle.hpp | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/cycle.hpp b/cycle.hpp index 20be700b..605aa2ab 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -29,14 +29,10 @@ namespace iter { friend Cycle> cycle( std::initializer_list &&); - - - - Container & container; // Value constructor for use only in the cycle function - Cycle(Container && container) : container(container) { } + Cycle(Container && container) : container{container} { } Cycle () = delete; Cycle & operator=(const Cycle &) = delete; @@ -50,10 +46,10 @@ namespace iter { const iterator_type end; public: Iterator (iterator_type iter, - iterator_type end) : - sub_iter(iter), - begin(iter), - end(end) + iterator_type end) + : sub_iter{iter}, + begin{iter}, + end{end} { } iterator_deref operator*() const { @@ -79,13 +75,13 @@ namespace iter { }; Iterator begin() const { - return Iterator(std::begin(this->container), - std::end(this->container)); + return {std::begin(this->container), + std::end(this->container)}; } Iterator end() const { - return Iterator(std::end(this->container), - std::end(this->container)); + return {std::end(this->container), + std::end(this->container)}; } }; @@ -93,13 +89,13 @@ namespace iter { // Helper function to instantiate an Filter template Cycle cycle(Container && container) { - return Cycle(std::forward(container)); + return {std::forward(container)}; } template Cycle> cycle(std::initializer_list && il) { - return Cycle>(std::move(il)); + return {std::move(il)}; } } From 18443899f35a8ffbe5edeca791f5c3a119cbb29f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 24 Jan 2014 03:26:29 -0500 Subject: [PATCH 0287/1866] uniform initialization updates --- dropwhile.hpp | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index 626ac733..2d298425 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -32,15 +32,10 @@ namespace iter { template friend DropWhile> dropwhile( FF, std::initializer_list &&); - - - - - // Value constructor for use only in the dropwhile function - DropWhile(FilterFunc filter_func, Container && container) : - container(container), + DropWhile(FilterFunc filter_func, Container && container) + : container{container}, filter_func(filter_func) { } DropWhile () = delete; @@ -65,9 +60,9 @@ namespace iter { public: Iterator (iterator_type iter, iterator_type end, - FilterFunc filter_func) : - sub_iter(iter), - sub_end(end), + FilterFunc filter_func) + : sub_iter{iter}, + sub_end{end}, filter_func(filter_func) { this->skip_passes(); @@ -88,17 +83,15 @@ namespace iter { }; Iterator begin() const { - return Iterator( - std::begin(this->container), + return {std::begin(this->container), std::end(this->container), - this->filter_func); + this->filter_func}; } Iterator end() const { - return Iterator( - std::end(this->container), + return {std::end(this->container), std::end(this->container), - this->filter_func); + this->filter_func}; } }; @@ -107,18 +100,14 @@ namespace iter { template DropWhile dropwhile( FilterFunc filter_func, Container && container) { - return DropWhile( - filter_func, - std::forward(container)); + return {filter_func, std::forward(container)}; } template DropWhile> dropwhile( FilterFunc filter_func, std::initializer_list && il) { - return DropWhile>( - filter_func, - std::move(il)); + return {filter_func, std::move(il)}; } } From 2c91f0558ec1da1888ffce6659f635813d6043dd Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 24 Jan 2014 14:45:02 -0500 Subject: [PATCH 0288/1866] uniform initialization updates --- filter.hpp | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/filter.hpp b/filter.hpp index 2decb950..143cc9e8 100644 --- a/filter.hpp +++ b/filter.hpp @@ -34,12 +34,9 @@ namespace iter { friend Filter> filter( FF, std::initializer_list &&); - - - // Value constructor for use only in the filter function - Filter(FilterFunc filter_func, Container && container) : - container(container), + Filter(FilterFunc filter_func, Container && container) + : container{container}, filter_func(filter_func) { } Filter () = delete; @@ -66,9 +63,9 @@ namespace iter { public: Iterator (iterator_type iter, iterator_type end, - FilterFunc filter_func) : - sub_iter(iter), - sub_end(end), + FilterFunc filter_func) + : sub_iter{iter}, + sub_end{end}, filter_func(filter_func) { this->skip_failures(); @@ -90,17 +87,15 @@ namespace iter { }; Iterator begin() const { - return Iterator( - std::begin(this->container), + return {std::begin(this->container), std::end(this->container), - this->filter_func); + this->filter_func}; } Iterator end() const { - return Iterator( - std::end(this->container), + return {std::end(this->container), std::end(this->container), - this->filter_func); + this->filter_func}; } }; @@ -109,8 +104,7 @@ namespace iter { template Filter filter( FilterFunc filter_func, Container && container) { - return Filter( - filter_func, std::forward(container)); + return {filter_func, std::forward(container)}; } template @@ -118,8 +112,7 @@ namespace iter { FilterFunc filter_func, std::initializer_list && il) { - return Filter>( - filter_func, std::move(il)); + return {filter_func, std::move(il)}; } namespace detail { From bd278b59c333b78f7ba05e245b0771fdf8bb6ade Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 24 Jan 2014 14:52:23 -0500 Subject: [PATCH 0289/1866] uniform initialization updates --- groupby.hpp | 46 ++++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index ed6fe0d0..c4868897 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -39,8 +39,8 @@ namespace iter { decltype(std::declval()( std::declval>())); - GroupBy(Container && container, KeyFunc key_func) : - container(container), + GroupBy(Container && container, KeyFunc key_func) + : container{container}, key_func(key_func) { } @@ -68,9 +68,9 @@ namespace iter { public: Iterator (iterator_type si, iterator_type end, - KeyFunc key_func) : - sub_iter(si), - sub_end(end), + KeyFunc key_func) + : sub_iter{si}, + sub_end{end}, key_func(key_func) { } @@ -148,10 +148,10 @@ namespace iter { Group & operator=(const Group &) = delete; Group & operator=(Group &&) = default; - Group (Group && other) : - owner(other.owner), - key(other.key), - completed(other.completed) { + Group (Group && other) + : owner{other.owner}, + key{other.key}, + completed{other.completed} { other.completed = true; } @@ -167,9 +167,9 @@ namespace iter { public: GroupIterator(const Group & group, - key_func_ret key) : - key(key), - group(group) + key_func_ret key) + : key{key}, + group{group} { } GroupIterator(const GroupIterator &) = default; @@ -194,28 +194,26 @@ namespace iter { }; GroupIterator begin() const { - return GroupIterator(*this, key); + return {*this, key}; } GroupIterator end() const { - return GroupIterator(*this, key); + return {*this, key}; } }; Iterator begin() const { - return Iterator( - std::begin(this->container), + return {std::begin(this->container), std::end(this->container), - this->key_func); + this->key_func}; } Iterator end() const { - return Iterator( + return {std::end(this->container), std::end(this->container), - std::end(this->container), - this->key_func); + this->key_func}; } }; @@ -236,9 +234,7 @@ namespace iter { template GroupBy groupby( Container && container, KeyFunc key_func) { - return GroupBy( - std::forward(container), - key_func); + return {std::forward(container), key_func}; } @@ -254,9 +250,7 @@ namespace iter { template GroupBy, KeyFunc> groupby( std::initializer_list && il, KeyFunc key_func) { - return GroupBy, KeyFunc>( - std::move(il), - key_func); + return {std::move(il), key_func}; } From ca3d108e93c44d10636a14ab142c69f930c0140c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 24 Jan 2014 14:54:50 -0500 Subject: [PATCH 0290/1866] uniform initialization updates --- imap.hpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/imap.hpp b/imap.hpp index ea447f81..6eeaaae8 100644 --- a/imap.hpp +++ b/imap.hpp @@ -125,11 +125,11 @@ namespace iter { }; Iterator begin() const { - return Iterator(this->map_func, this->zipped.begin()); + return {this->map_func, this->zipped.begin()}; } Iterator end() const { - return Iterator(this->map_func, this->zipped.end()); + return {this->map_func, this->zipped.end()}; } }; @@ -138,9 +138,7 @@ namespace iter { template IMap imap( MapFunc map_func, Containers && ... containers) { - return IMap( - map_func, - std::forward(containers)...); + return {map_func, std::forward(containers)...}; } } From 7937edde6f81be4bc7e4efd92266d4608612e1e8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 24 Jan 2014 14:57:45 -0500 Subject: [PATCH 0291/1866] uniform initialization updates --- slice.hpp | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/slice.hpp b/slice.hpp index 2415225e..f7a074a4 100644 --- a/slice.hpp +++ b/slice.hpp @@ -72,11 +72,11 @@ namespace iter { public: Slice(Container & container, DifferenceType start, - DifferenceType stop, DifferenceType step) : - container(container), - start(start), - stop(stop), - step(step) + DifferenceType stop, DifferenceType step) + : container{container}, + start{start}, + stop{stop}, + step{step} { // sets stop = start if the range is empty if ((start < stop && step <=0) || @@ -106,11 +106,11 @@ namespace iter { public: Iterator (iterator_type si, DifferenceType start, - DifferenceType stop, DifferenceType step) : - sub_iter(si), - current(start), - stop(stop), - step(step) + DifferenceType stop, DifferenceType step) + : sub_iter{si}, + current{start}, + stop{stop}, + step{step} { } iterator_deref operator*() const { @@ -130,15 +130,13 @@ namespace iter { }; Iterator begin() const { - return Iterator( - std::next(std::begin(this->container), this->start), - this->start, this->stop, this->step); + return {std::next(std::begin(this->container), this->start), + this->start, this->stop, this->step}; } Iterator end() const { - return Iterator( - std::next(std::begin(this->container), this->stop), - this->stop, this->stop, this->step); + return {std::next(std::begin(this->container), this->stop), + this->stop, this->stop, this->step}; } }; @@ -148,30 +146,27 @@ namespace iter { Slice slice( Container && container, DifferenceType start, DifferenceType stop, DifferenceType step=1) { - return Slice( - std::forward(container), start, stop, step); + return {std::forward(container), start, stop, step}; } //only give the end as an arg and assume step is 1 and begin is 0 template Slice slice( Container && container, DifferenceType stop) { - return Slice( - std::forward(container), 0, stop, 1); + return {std::forward(container), 0, stop, 1}; } template Slice, DifferenceType> slice( std::initializer_list && il, DifferenceType start, DifferenceType stop, DifferenceType step=1) { - return Slice, DifferenceType>( - il, start, stop, step); + return {il, start, stop, step}; } template Slice, DifferenceType> slice( std::initializer_list && il, DifferenceType stop) { - return Slice, DifferenceType>(il, 0, stop, 1); + return {il, 0, stop, 1}; } } From c8f9dfec4162a1f8591d845fb4f26ba38eeed1e1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 24 Jan 2014 16:30:49 -0500 Subject: [PATCH 0292/1866] uniform initialization updates --- sorted.hpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/sorted.hpp b/sorted.hpp index 6a0c518a..ce824541 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -20,10 +20,6 @@ namespace iter { friend Sorted sorted(Container &, CompareFunc); - - - - std::vector> sorted_iters; using sorted_iter_type = decltype(std::begin(sorted_iters)); @@ -55,8 +51,8 @@ namespace iter { // them when accessed with operator * class IteratorIterator : public sorted_iter_type { public: - IteratorIterator(sorted_iter_type iter) : - sorted_iter_type(iter) + IteratorIterator(sorted_iter_type iter) + : sorted_iter_type{iter} { } IteratorIterator(const IteratorIterator &) = default; @@ -67,20 +63,19 @@ namespace iter { }; IteratorIterator begin() { - IteratorIterator iteriter(std::begin(sorted_iters)); - return iteriter; + return {std::begin(sorted_iters)}; + } IteratorIterator end() { - IteratorIterator iteriter(std::end(sorted_iters)); - return iteriter; + return {std::end(sorted_iters)}; } }; template Sorted sorted( Container & container, CompareFunc compare_func) { - return Sorted(container, compare_func); + return {container, compare_func}; } template From a129fc7d632c1bd9f19462438a291a07c3eadc8a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 24 Jan 2014 16:33:50 -0500 Subject: [PATCH 0293/1866] uniform initialization updates --- takewhile.hpp | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/takewhile.hpp b/takewhile.hpp index caf135d3..92937e20 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -33,13 +33,9 @@ namespace iter { friend TakeWhile> takewhile( FF, std::initializer_list &&); - - - - // Value constructor for use only in the takewhile function - TakeWhile(FilterFunc filter_func, Container && container) : - container(container), + TakeWhile(FilterFunc filter_func, Container && container) + : container{container}, filter_func(filter_func) { } @@ -71,9 +67,9 @@ namespace iter { public: Iterator (iterator_type iter, iterator_type end, - FilterFunc filter_func) : - sub_iter(iter), - sub_end(end), + FilterFunc filter_func) + : sub_iter{iter}, + sub_end{end}, filter_func(filter_func) { if (this->sub_iter != this->sub_end) { @@ -98,17 +94,15 @@ namespace iter { }; Iterator begin() const { - return Iterator( - std::begin(this->container), + return {std::begin(this->container), std::end(this->container), - this->filter_func); + this->filter_func}; } Iterator end() const { - return Iterator( - std::end(this->container), + return {std::end(this->container), std::end(this->container), - this->filter_func); + this->filter_func}; } }; @@ -117,18 +111,14 @@ namespace iter { template TakeWhile takewhile( FilterFunc filter_func, Container && container) { - return TakeWhile( - filter_func, - std::forward(container)); + return {filter_func, std::forward(container)}; } template TakeWhile> takewhile( FilterFunc filter_func, std::initializer_list && il) { - return TakeWhile>( - filter_func, - std::move(il)); + return {filter_func, std::move(il)}; } } From 87b3f990569d753a8abdb6c170f7bdde1bf7cbbe Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 6 Mar 2014 10:13:41 -0500 Subject: [PATCH 0294/1866] Renames "moving_section" to "sliding_window" Inspired by the networking algorithm. This name better conveys the purpose and functionality of the iterable. --- README.md | 6 ++-- grouper.hpp | 2 +- itertools.hpp | 2 +- moving_section.hpp => sliding_window.hpp | 30 +++++++++---------- tests/.gitignore | 2 +- tests/SConstruct | 4 +-- tests/testcommand_chains.cpp | 2 +- ...ing_section.cpp => testsliding_window.cpp} | 6 ++-- 8 files changed, 27 insertions(+), 27 deletions(-) rename moving_section.hpp => sliding_window.hpp (74%) rename tests/{testmoving_section.cpp => testsliding_window.cpp} (71%) diff --git a/README.md b/README.md index 20eee131..a4a1770d 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ library. [chain](#chain)
[reverse](#reverse)
[slice](#slice)
-[moving_section](#moving_section)
+[sliding_window](#sliding_window)
[grouper](#grouper)
##### Combinatoric fuctions @@ -350,7 +350,7 @@ for (auto i : slice(a,0,15,3)) { } ``` -moving_section +sliding_window ------------- Takes a section from a range and increments the whole section. @@ -371,7 +371,7 @@ take a section of size 4, output is: Example Usage: ```c++ std::vector v = {1,2,3,4,5,6,7,8,9}; -for (auto sec : moving_section(v,4)) { +for (auto sec : sliding_window(v,4)) { for (auto i : sec) { std::cout << i << " "; i.get() = 90; diff --git a/grouper.hpp b/grouper.hpp index eb885e27..192fd255 100644 --- a/grouper.hpp +++ b/grouper.hpp @@ -63,7 +63,7 @@ namespace iter { // this->group.push_back(this->container.begin() + i); } - //seems like conclassor is same as moving_section_iter + //seems like conclassor is same as sliding_window_iter grouper_iter(Container && c) : container(std::forward(c)) { diff --git a/itertools.hpp b/itertools.hpp index 4129c4c7..5b038ef8 100644 --- a/itertools.hpp +++ b/itertools.hpp @@ -15,7 +15,7 @@ #include "grouper.hpp" #include "imap.hpp" #include "iterator_range.hpp" -#include "moving_section.hpp" +#include "sliding_window.hpp" #include "permutations.hpp" #include "powerset.hpp" #include "product.hpp" diff --git a/moving_section.hpp b/sliding_window.hpp similarity index 74% rename from moving_section.hpp rename to sliding_window.hpp index 3ee6eb9b..a7bea87e 100644 --- a/moving_section.hpp +++ b/sliding_window.hpp @@ -1,5 +1,5 @@ -#ifndef MOVING_SECTION_HPP -#define MOVING_SECTION_HPP +#ifndef SLIDING_WINDOW_HPP +#define SLIDING_WINDOW_HPP #include "iterator_range.hpp" @@ -12,17 +12,17 @@ namespace iter { template - struct moving_section_iter; + struct sliding_window_iter; template - iterator_range> - moving_section(Container && container, size_t s) { - auto begin = moving_section_iter(std::forward(container),s); - auto end = moving_section_iter(std::forward(container)); - return iterator_range>(begin,end); + iterator_range> + sliding_window(Container && container, size_t s) { + auto begin = sliding_window_iter(std::forward(container),s); + auto end = sliding_window_iter(std::forward(container)); + return iterator_range>(begin,end); } template - struct moving_section_iter { + struct sliding_window_iter { typename std::conditional::value, Container&, @@ -32,7 +32,7 @@ namespace iter { using Iterator = decltype(std::begin(container)); std::vector section; size_t section_size = 0; - moving_section_iter(Container && c, size_t s) : + sliding_window_iter(Container && c, size_t s) : container(std::forward(c)),section_size(s) { size_t i = 0; for (auto iter = std::begin(container); i < section_size;++iter,++i) { @@ -41,20 +41,20 @@ namespace iter { //for (size_t i = 0; i < section_size; ++i) // section.push_back(container.begin()+i); } - moving_section_iter(Container && c) : container(std::forward(c)) + sliding_window_iter(Container && c) : container(std::forward(c)) //creates the end iterator { section.push_back(std::end(container)); } - moving_section_iter & operator++() { + sliding_window_iter & operator++() { for (auto & iter : section) { ++iter; } return *this; //std::for_each(section.begin(),section.end(),[](Iterator & i){++i;}); } - bool operator!=(const moving_section_iter & rhs) { + bool operator!=(const sliding_window_iter & rhs) { return this->section.back() != rhs.section.back(); } using Deref_type = std::vector())>::type>>; @@ -70,9 +70,9 @@ namespace iter { } namespace std { template - struct iterator_traits> { + struct iterator_traits> { using difference_type = ptrdiff_t; using iterator_category = input_iterator_tag; }; } -#endif //MOVING_SECTION_HPP +#endif //SLIDING_WINDOW_HPP diff --git a/tests/.gitignore b/tests/.gitignore index 3daf97d6..a78678de 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -18,7 +18,7 @@ testcombinations_with_replacement testtakewhile testcombinations testpowerset -testmoving_section +testsliding_window testimap testfilterfalse testcount diff --git a/tests/SConstruct b/tests/SConstruct index 56b5aa44..17e40444 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -2,7 +2,7 @@ import platform import os env = Environment( - CXX='c++', + CXX='g++', CXXFLAGS= ['-g', '-Wall', '-Wextra', '-pedantic', '-std=c++11', '-I/usr/local/include'], @@ -30,7 +30,7 @@ progs = Split(''' combinations_with_replacement combinations powerset - moving_section + sliding_window imap count filterfalse diff --git a/tests/testcommand_chains.cpp b/tests/testcommand_chains.cpp index 76aca6f4..07cae5c5 100644 --- a/tests/testcommand_chains.cpp +++ b/tests/testcommand_chains.cpp @@ -47,7 +47,7 @@ int main() { { std::vector vec1{1,2,3,4,5,6}; std::vector vec2{7,8,9,10}; - for (auto s : moving_section(chain(vec1,vec2),4)) { + for (auto s : sliding_window(chain(vec1,vec2),4)) { for (auto i : s) std::cout << i << " "; std::cout< #include -using iter::moving_section; +using iter::sliding_window; int main() { std::vector v = {1,2,3,4,5,6,7,8,9}; - for (auto sec : moving_section(v,4)) { + for (auto sec : sliding_window(v,4)) { for (auto i : sec) { std::cout << i << " "; i.get() = 90; From 4447a1aba42f3d6a0871ab9bfcbb7cdef66842af Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 1 May 2014 10:31:12 -0400 Subject: [PATCH 0295/1866] adds missing "if" to README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a4a1770d..07b24d3f 100644 --- a/README.md +++ b/README.md @@ -230,7 +230,7 @@ for (auto gb : groupby(vec, [] (const string &s) {return s.length(); })) { ``` *Note*: Just like Python's `itertools.groupby`, this doesn't do any sorting. It just iterates through, making a new group each time there is a key change. -Thus, the the group is unsorted, the same key may appear multiple times. +Thus, if the the group is unsorted, the same key may appear multiple times. zip --- From a91a8138be1ffdd7853c5674da95e4543133bf15 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 1 May 2014 10:34:11 -0400 Subject: [PATCH 0296/1866] adds note about lazy evaluation --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 07b24d3f..03dcf0ff 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ CPPItertools ============ -range-based for loop add-ons inspired by the python builtins and itertools -library. +range-based for loop add-ons inspired by the Python builtins and itertools +library. Like itertools and the Python3 builtins, this library uses lazy +evaluation wherever possible. *Note*: Everthing is inside the `iter` namespace. From bddd463189d1ae500a6ecba5f4e63145f41ab0a1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 25 May 2014 12:59:45 -0700 Subject: [PATCH 0297/1866] adds non-functional accumulate --- accumulate.hpp | 114 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 accumulate.hpp diff --git a/accumulate.hpp b/accumulate.hpp new file mode 100644 index 00000000..cb189ea6 --- /dev/null +++ b/accumulate.hpp @@ -0,0 +1,114 @@ +#ifndef accumulate__H__ +#define accumulate__H__ + +#include "iterbase.hpp" + +#include +#include +#include + +namespace iter { + + //Forward declarations of Accumulator and accumulate + template + class Accumulator; + + template + Accumulator accumulate( + Container &&, AccumulateFunc); + + template + Accumulator> accumulate( + std::initializer_list &&, AccumulateFunc); + + template + class Accumulator { + private: + Container & container; + AccumulateFunc accumulate_func; + + // The accumulate function is the only thing allowed to create a Accumulator + friend Accumulator accumulate( + Container &&, AccumulateFunc); + + template + friend Accumulator, AF> accumulate( + std::initializer_list &&, AF); + + // Value constructor for use only in the accumulate function + Accumulator(AccumulateFunc accumulate_func, Container && container) + : container{container}, + accumulate_func(accumulate_func) + { } + Accumulator () = delete; + Accumulator & operator=(const Accumulator &) = delete; + + public: + Accumulator(const Accumulator &) = default; + + class Iterator { + using AccumVal = + typename std::result_of, iterator_deref)>::type; + private: + iterator_type sub_iter; + const iterator_type sub_end; + AccumulateFunc accumulate_func; + public: + Iterator (iterator_type iter, + iterator_type end, + AccumulateFunc accumulate_func) + : sub_iter{iter}, + sub_end{end}, + accumulate_func(accumulate_func) + { } + + iterator_deref operator*() const { + return *this->sub_iter; + } + + Iterator & operator++() { + ++this->sub_iter; + // TODO + return *this; + } + + bool operator!=(const Iterator & other) const { + return this->sub_iter != other.sub_iter; + } + }; + + Iterator begin() const { + return {std::begin(this->container), + std::end(this->container), + this->accumulate_func}; + } + + Iterator end() const { + return {std::end(this->container), + std::end(this->container), + this->accumulate_func}; + } + + }; + + // Helper function to instantiate an Accumulator + template + Accumulator accumulate( + Container && container, + AccumulateFunc accumulate_func) + { + return {accumulate_func, std::forward(container)}; + } + + template + Accumulator> accumulate( + std::initializer_list && il, + AccumulateFunc accumulate_func) + { + return {accumulate_func, std::move(il)}; + } + +} + +#endif //ifndef accumulate__H__ From f2b4d26705579c02780ca996c1b89cd8829d6bc3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 25 May 2014 14:34:29 -0700 Subject: [PATCH 0298/1866] accumulate actually works --- accumulate.hpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index cb189ea6..f67e048a 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -47,29 +47,36 @@ namespace iter { Accumulator(const Accumulator &) = default; class Iterator { + // NOTE can AccumVal and iterator_deref<> be different? using AccumVal = typename std::result_of, iterator_deref)>::type; + iterator_deref, + iterator_deref)>::type; private: iterator_type sub_iter; const iterator_type sub_end; AccumulateFunc accumulate_func; + AccumVal acc_val; public: Iterator (iterator_type iter, iterator_type end, AccumulateFunc accumulate_func) : sub_iter{iter}, sub_end{end}, - accumulate_func(accumulate_func) + accumulate_func(accumulate_func), + acc_val(iter == end ? AccumVal{} : *iter) { } - iterator_deref operator*() const { - return *this->sub_iter; + AccumVal operator*() const { + return this->acc_val; } Iterator & operator++() { ++this->sub_iter; - // TODO + if (this->sub_iter != this->sub_end) { + this->acc_val = accumulate_func( + this->acc_val, *this->sub_iter); + } return *this; } From faf79aaef04f6e782f094678e8ce31fc487dbe0c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 25 May 2014 15:10:45 -0700 Subject: [PATCH 0299/1866] rearranges template args --- accumulate.hpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index f67e048a..f64f4924 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -1,5 +1,5 @@ -#ifndef accumulate__H__ -#define accumulate__H__ +#ifndef ACCUMULATE__H__ +#define ACCUMULATE__H__ #include "iterbase.hpp" @@ -10,18 +10,18 @@ namespace iter { //Forward declarations of Accumulator and accumulate - template + template class Accumulator; template - Accumulator accumulate( + Accumulator accumulate( Container &&, AccumulateFunc); template - Accumulator> accumulate( + Accumulator, AccumulateFunc> accumulate( std::initializer_list &&, AccumulateFunc); - template + template class Accumulator { private: Container & container; @@ -36,7 +36,7 @@ namespace iter { std::initializer_list &&, AF); // Value constructor for use only in the accumulate function - Accumulator(AccumulateFunc accumulate_func, Container && container) + Accumulator(Container && container, AccumulateFunc accumulate_func) : container{container}, accumulate_func(accumulate_func) { } @@ -47,7 +47,6 @@ namespace iter { Accumulator(const Accumulator &) = default; class Iterator { - // NOTE can AccumVal and iterator_deref<> be different? using AccumVal = typename std::result_of, @@ -101,21 +100,21 @@ namespace iter { // Helper function to instantiate an Accumulator template - Accumulator accumulate( + Accumulator accumulate( Container && container, AccumulateFunc accumulate_func) { - return {accumulate_func, std::forward(container)}; + return {std::forward(container), accumulate_func}; } template - Accumulator> accumulate( + Accumulator, AccumulateFunc> accumulate( std::initializer_list && il, AccumulateFunc accumulate_func) { - return {accumulate_func, std::move(il)}; + return {std::move(il), accumulate_func}; } } -#endif //ifndef accumulate__H__ +#endif //ifndef ACCUMULATE__H__ From 91b2f7d0adb803edb26a472c087fa880014dd468 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 25 May 2014 15:13:47 -0700 Subject: [PATCH 0300/1866] removes use of iterator == iterator uses !(iterator != iterator) instead --- accumulate.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accumulate.hpp b/accumulate.hpp index f64f4924..ce48c9d8 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -63,7 +63,7 @@ namespace iter { : sub_iter{iter}, sub_end{end}, accumulate_func(accumulate_func), - acc_val(iter == end ? AccumVal{} : *iter) + acc_val(!(iter != end) ? AccumVal{} : *iter) { } AccumVal operator*() const { From 843b7563b60d56d24fbd34b714759ef90aab34f5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 25 May 2014 15:21:06 -0700 Subject: [PATCH 0301/1866] Support for initializer lists --- accumulate.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index ce48c9d8..dd3eee69 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -17,7 +17,7 @@ namespace iter { Accumulator accumulate( Container &&, AccumulateFunc); - template + template Accumulator, AccumulateFunc> accumulate( std::initializer_list &&, AccumulateFunc); @@ -31,7 +31,7 @@ namespace iter { friend Accumulator accumulate( Container &&, AccumulateFunc); - template + template friend Accumulator, AF> accumulate( std::initializer_list &&, AF); @@ -47,6 +47,7 @@ namespace iter { Accumulator(const Accumulator &) = default; class Iterator { + // AccumVal must be default constructible using AccumVal = typename std::result_of, From 19207660ca59a4e1c6b79f6c827fbb19f3a166c9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 25 May 2014 15:36:59 -0700 Subject: [PATCH 0302/1866] AccumulateFunc defaults to std::plus --- accumulate.hpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/accumulate.hpp b/accumulate.hpp index dd3eee69..ddb03dce 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace iter { @@ -108,6 +109,15 @@ namespace iter { return {std::forward(container), accumulate_func}; } + template + auto accumulate(Container && container) -> + decltype(accumulate(std::forward(container), + std::plus>{})) + { + return accumulate(std::forward(container), + std::plus>{}); + } + template Accumulator, AccumulateFunc> accumulate( std::initializer_list && il, @@ -116,6 +126,13 @@ namespace iter { return {std::move(il), accumulate_func}; } + template + auto accumulate(std::initializer_list && il) -> + decltype(accumulate(std::move(il), std::plus{})) + { + return accumulate(std::move(il), std::plus{}); + } + } #endif //ifndef ACCUMULATE__H__ From 5352d52e5ffb7ec1fda2fa75ec44a3c247f6cc55 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 25 May 2014 15:37:21 -0700 Subject: [PATCH 0303/1866] adds testaccumulate --- tests/testaccumulate.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 tests/testaccumulate.cpp diff --git a/tests/testaccumulate.cpp b/tests/testaccumulate.cpp new file mode 100644 index 00000000..a65bf7b9 --- /dev/null +++ b/tests/testaccumulate.cpp @@ -0,0 +1,29 @@ +#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'; + } + + return 0; +} From a32308971b51f9a5c87def5d4883dcb352a56400 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 25 May 2014 17:53:08 -0700 Subject: [PATCH 0304/1866] adds accumulate to the SConstruct --- tests/SConstruct | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/SConstruct b/tests/SConstruct index 17e40444..e38c0914 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -2,7 +2,7 @@ import platform import os env = Environment( - CXX='g++', + CXX='c++', CXXFLAGS= ['-g', '-Wall', '-Wextra', '-pedantic', '-std=c++11', '-I/usr/local/include'], @@ -13,6 +13,7 @@ env = Environment( env['ENV']['TERM'] = os.environ['TERM'] progs = Split(''' + accumulate cycle enumerate range From 693cf5aa2b2336d93d7e8d63e93e85b473ed3bc4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 25 May 2014 17:56:03 -0700 Subject: [PATCH 0305/1866] adds accumulate to .gitignore --- tests/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/.gitignore b/tests/.gitignore index a78678de..de362625 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,5 +1,6 @@ *.o *.swp +testaccumulate testchain testcycle testenumerate From 0c4602081fe23a346d423cc9b4916ebebd27303e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 25 May 2014 21:33:28 -0400 Subject: [PATCH 0306/1866] adds accumulate to README --- README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/README.md b/README.md index 03dcf0ff..f16cc894 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ evaluation wherever possible. [dropwhile](#dropwhile)
[cycle](#cycle)
[groupby](#groupby)
+[accumulate](#accumulate)
[compress](#compress)
[chain](#chain)
[reverse](#reverse)
@@ -233,6 +234,31 @@ 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. +accumulate +------- +Differs from `std::accumulate` (which in my humble opinion should be named +`std::reduce` or `std::foldl`). It is imilar to a functional reduce where one +can see all of the intermediate results. By default, it keeps a running sum. +Prints: `1 3 6 10 15` +```c++ +for (auto i : accumulate(range(1, 6))) { + cout << i << '\n'; +} +``` +A second, optional argument may provide an alternative binary function +to compute results. The following example multiplies the numbers, rather +than adding them. +Prints: `1 2 6 24 120` + +```c++ +for (auto i : accumulate(range(1, 6), std::multiplies{})) { + cout << i << '\n'; +} +``` + +Note: The intermediate result type must support default construction +and assignment. + zip --- From 23def64dc5fa948bc183eed0f0d891f44fe3c04c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 25 May 2014 21:34:16 -0400 Subject: [PATCH 0307/1866] typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f16cc894..d8a4bd0b 100644 --- a/README.md +++ b/README.md @@ -237,7 +237,7 @@ Thus, if the the group is unsorted, the same key may appear multiple times. accumulate ------- Differs from `std::accumulate` (which in my humble opinion should be named -`std::reduce` or `std::foldl`). It is imilar to a functional reduce where one +`std::reduce` or `std::foldl`). It is similar to a functional reduce where one can see all of the intermediate results. By default, it keeps a running sum. Prints: `1 3 6 10 15` ```c++ From ce794cfee9119e36d376d1f723a4b2b29c60ec85 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 12:10:22 -0700 Subject: [PATCH 0308/1866] formats enumerate --- enumerate.hpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 7cb61263..fb34d534 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -25,11 +25,10 @@ namespace iter { class Enumerable; template - Enumerable> enumerate( - std::initializer_list &&); + Enumerable> enumerate(std::initializer_list&&); template - Enumerable enumerate(Container &&); + Enumerable enumerate(Container&&); template class Enumerable { @@ -38,19 +37,19 @@ namespace iter { // The only thing allowed to directly instantiate an Enumerable is // the enumerate function - friend Enumerable enumerate(Container &&); + friend Enumerable enumerate(Container&&); template friend Enumerable> enumerate( - std::initializer_list &&); + std::initializer_list&&); - Enumerable(Container && container) : container{container} { } + Enumerable(Container&& container) : container{container} { } public: // Value constructor for use only in the enumerate function Enumerable () = delete; - Enumerable & operator=(const Enumerable &) = delete; + Enumerable & operator=(const Enumerable&) = delete; - Enumerable(const Enumerable &) = default; + Enumerable(const Enumerable&) = default; // "yielded" by the Enumerable::Iterator. Has a .index, and a // .element referencing the value yielded by the subiterator @@ -104,13 +103,13 @@ namespace iter { // Helper function to instantiate an Enumerable template - Enumerable enumerate(Container && container) { + Enumerable enumerate(Container&& container) { return {std::forward(container)}; } template Enumerable> enumerate( - std::initializer_list && il) + std::initializer_list&& il) { return {std::move(il)}; } From a871e252b275a9a98195109bd777a90f574d8dc4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 12:11:12 -0700 Subject: [PATCH 0309/1866] formats accumulate --- accumulate.hpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index ddb03dce..d690dd74 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -16,11 +16,11 @@ namespace iter { template Accumulator accumulate( - Container &&, AccumulateFunc); + Container&&, AccumulateFunc); template Accumulator, AccumulateFunc> accumulate( - std::initializer_list &&, AccumulateFunc); + std::initializer_list&&, AccumulateFunc); template class Accumulator { @@ -30,22 +30,22 @@ namespace iter { // The accumulate function is the only thing allowed to create a Accumulator friend Accumulator accumulate( - Container &&, AccumulateFunc); + Container&&, AccumulateFunc); template friend Accumulator, AF> accumulate( - std::initializer_list &&, AF); + std::initializer_list&&, AF); // Value constructor for use only in the accumulate function - Accumulator(Container && container, AccumulateFunc accumulate_func) + Accumulator(Container&& container, AccumulateFunc accumulate_func) : container{container}, accumulate_func(accumulate_func) { } Accumulator () = delete; - Accumulator & operator=(const Accumulator &) = delete; + Accumulator & operator=(const Accumulator&) = delete; public: - Accumulator(const Accumulator &) = default; + Accumulator(const Accumulator&) = default; class Iterator { // AccumVal must be default constructible @@ -65,6 +65,7 @@ namespace iter { : sub_iter{iter}, sub_end{end}, accumulate_func(accumulate_func), + // only get first value if not an end iterator acc_val(!(iter != end) ? AccumVal{} : *iter) { } @@ -103,14 +104,14 @@ namespace iter { // Helper function to instantiate an Accumulator template Accumulator accumulate( - Container && container, + Container&& container, AccumulateFunc accumulate_func) { return {std::forward(container), accumulate_func}; } template - auto accumulate(Container && container) -> + auto accumulate(Container&& container) -> decltype(accumulate(std::forward(container), std::plus>{})) { @@ -120,14 +121,14 @@ namespace iter { template Accumulator, AccumulateFunc> accumulate( - std::initializer_list && il, + std::initializer_list&& il, AccumulateFunc accumulate_func) { return {std::move(il), accumulate_func}; } template - auto accumulate(std::initializer_list && il) -> + auto accumulate(std::initializer_list&& il) -> decltype(accumulate(std::move(il), std::plus{})) { return accumulate(std::move(il), std::plus{}); From a0cba79f8f1e0f3145faf07408c98890eb963eea Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 12:29:20 -0700 Subject: [PATCH 0310/1866] formats compress --- compress.hpp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/compress.hpp b/compress.hpp index 376f432a..be56bec1 100644 --- a/compress.hpp +++ b/compress.hpp @@ -13,19 +13,19 @@ namespace iter { class Compressed; template - Compressed compress(Container &&, Selector &&); + Compressed compress(Container&&, Selector&&); template Compressed, Selector> compress( - std::initializer_list &&, Selector &&); + std::initializer_list&&, Selector&&); template Compressed> compress( - Container &&, std::initializer_list &&); + Container&&, std::initializer_list&&); template Compressed, std::initializer_list> compress( - std::initializer_list &&, std::initializer_list &&); + std::initializer_list&&, std::initializer_list&&); template class Compressed { @@ -36,34 +36,34 @@ namespace iter { // The only thing allowed to directly instantiate an Compressed is // the compress function friend Compressed compress( - Container &&, Selector &&); + Container&&, Selector&&); template friend Compressed, Sel> compress( - std::initializer_list &&, Sel &&); + std::initializer_list&&, Sel&&); template friend Compressed> compress( - Con &&, std::initializer_list &&); + Con&&, std::initializer_list&&); template friend Compressed, std::initializer_list> compress( - std::initializer_list &&, std::initializer_list &&); + std::initializer_list&&, std::initializer_list&&); // Selector::Iterator type using selector_iter_type = decltype(std::begin(selectors)); // Value constructor for use only in the compress function - Compressed(Container && container, Selector && selectors) + Compressed(Container&& container, Selector&& selectors) : container{container}, selectors{selectors} { } - Compressed () = delete; - Compressed & operator=(const Compressed &) = delete; + Compressed() = delete; + Compressed& operator=(const Compressed&) = delete; public: - Compressed (const Compressed &) = default; + Compressed(const Compressed&) = default; class Iterator { private: @@ -130,29 +130,29 @@ namespace iter { // Helper function to instantiate an Compressed template Compressed compress( - Container && container, Selector && selectors) { + Container&& container, Selector&& selectors) { return {std::forward(container), std::forward(selectors)}; } template Compressed, Selector> compress( - std::initializer_list && data, Selector && selectors) { + std::initializer_list&& data, Selector&& selectors) { return {std::move(data), std::forward(selectors)}; } template Compressed> compress( - Container && container, std::initializer_list && selectors) { + Container&& container, std::initializer_list&& selectors) { return {std::forward(container), std::move(selectors)}; } template Compressed, std::initializer_list> compress( - std::initializer_list && data, - std::initializer_list && selectors) { + std::initializer_list&& data, + std::initializer_list&& selectors) { return {std::move(data), std::move(selectors)}; } From 6b03d9b05caae961ad3b38ca445a5662c8a58d79 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 12:31:19 -0700 Subject: [PATCH 0311/1866] formats cycle --- cycle.hpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/cycle.hpp b/cycle.hpp index 605aa2ab..8d5245bf 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -14,30 +14,29 @@ namespace iter { class Cycle; template - Cycle cycle(Container &&); + Cycle cycle(Container&&); template - Cycle> cycle( - std::initializer_list &&); + Cycle> cycle(std::initializer_list&&); template class Cycle { private: // The cycle function is the only thing allowed to create a Cycle - friend Cycle cycle(Container &&); + friend Cycle cycle(Container&&); template friend Cycle> cycle( - std::initializer_list &&); + std::initializer_list&&); Container & container; // Value constructor for use only in the cycle function - Cycle(Container && container) : container{container} { } - Cycle () = delete; - Cycle & operator=(const Cycle &) = delete; + Cycle(Container&& container) : container{container} { } + Cycle() = delete; + Cycle& operator=(const Cycle&) = delete; public: - Cycle(const Cycle &) = default; + Cycle(const Cycle&) = default; class Iterator { private: using iter_type = iterator_type; @@ -88,12 +87,12 @@ namespace iter { // Helper function to instantiate an Filter template - Cycle cycle(Container && container) { + Cycle cycle(Container&& container) { return {std::forward(container)}; } template - Cycle> cycle(std::initializer_list && il) + Cycle> cycle(std::initializer_list&& il) { return {std::move(il)}; } From 2e166a3fc5eefedec17edc91ce1cd59e5fd29528 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 12:38:25 -0700 Subject: [PATCH 0312/1866] formats enumerate --- enumerate.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enumerate.hpp b/enumerate.hpp index fb34d534..849c7533 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -33,7 +33,7 @@ namespace iter { template class Enumerable { private: - Container & container; + Container& container; // The only thing allowed to directly instantiate an Enumerable is // the enumerate function From 4abe724a9341d3e7f4faad907b13e5c37a7d3235 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 12:38:50 -0700 Subject: [PATCH 0313/1866] formats accumulate --- accumulate.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accumulate.hpp b/accumulate.hpp index d690dd74..0e07bf47 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -25,7 +25,7 @@ namespace iter { template class Accumulator { private: - Container & container; + Container& container; AccumulateFunc accumulate_func; // The accumulate function is the only thing allowed to create a Accumulator From 096fc81b89e4f64c953e0197b2f62962dc1a9541 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 12:39:13 -0700 Subject: [PATCH 0314/1866] formats compress --- compress.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compress.hpp b/compress.hpp index be56bec1..b18d7d0b 100644 --- a/compress.hpp +++ b/compress.hpp @@ -30,7 +30,7 @@ namespace iter { template class Compressed { private: - Container & container; + Container& container; Selector & selectors; // The only thing allowed to directly instantiate an Compressed is From 5e566820cb9f829de114205c1f5b8c8e2a3ac0c8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 12:39:38 -0700 Subject: [PATCH 0315/1866] formats cycle --- cycle.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cycle.hpp b/cycle.hpp index 8d5245bf..13c4b1f0 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -28,7 +28,7 @@ namespace iter { friend Cycle> cycle( std::initializer_list&&); - Container & container; + Container& container; // Value constructor for use only in the cycle function Cycle(Container&& container) : container{container} { } From 65477d6606846534578ff2d19cb47044b57001b3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 12:40:36 -0700 Subject: [PATCH 0316/1866] formats dropwhile --- dropwhile.hpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index 2d298425..0393845e 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -14,35 +14,35 @@ namespace iter { class DropWhile; template - DropWhile dropwhile(FilterFunc, Container &&); + DropWhile dropwhile(FilterFunc, Container&&); template DropWhile> dropwhile( - FilterFunc, std::initializer_list &&); + FilterFunc, std::initializer_list&&); template class DropWhile { private: - Container & container; + Container& container; FilterFunc filter_func; friend DropWhile dropwhile( - FilterFunc, Container &&); + FilterFunc, Container&&); template friend DropWhile> dropwhile( - FF, std::initializer_list &&); + FF, std::initializer_list&&); // Value constructor for use only in the dropwhile function - DropWhile(FilterFunc filter_func, Container && container) + DropWhile(FilterFunc filter_func, Container&& container) : container{container}, filter_func(filter_func) { } - DropWhile () = delete; - DropWhile & operator=(const DropWhile &) = delete; + DropWhile() = delete; + DropWhile& operator=(const DropWhile&) = delete; public: - DropWhile(const DropWhile &) = default; + DropWhile(const DropWhile&) = default; class Iterator { private: iterator_type sub_iter; @@ -99,13 +99,13 @@ namespace iter { // Helper function to instantiate a DropWhile template DropWhile dropwhile( - FilterFunc filter_func, Container && container) { + FilterFunc filter_func, Container&& container) { return {filter_func, std::forward(container)}; } template DropWhile> dropwhile( - FilterFunc filter_func, std::initializer_list && il) + FilterFunc filter_func, std::initializer_list&& il) { return {filter_func, std::move(il)}; } From 6bafad489ae453419d02d5266c981a71b85d63a0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 12:42:48 -0700 Subject: [PATCH 0317/1866] formats filterfalse --- filterfalse.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/filterfalse.hpp b/filterfalse.hpp index dfd2716c..3beaaef3 100644 --- a/filterfalse.hpp +++ b/filterfalse.hpp @@ -23,7 +23,7 @@ namespace iter { { } PredicateFlipper() = delete; - PredicateFlipper(const PredicateFlipper &) = default; + PredicateFlipper(const PredicateFlipper&) = default; // Calls the filter_func bool operator() (const iterator_deref item) const { @@ -48,7 +48,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) -> + auto filterfalse(FilterFunc filter_func, Container&& container) -> decltype(filter( detail::PredicateFlipper( filter_func), @@ -61,7 +61,7 @@ namespace iter { // Single argument version, uses a BoolFlipper to reverse the truthiness // of an object template - auto filterfalse(Container && container) -> + auto filterfalse(Container&& container) -> decltype(filter( detail::BoolFlipper(), std::forward(container))) { @@ -74,7 +74,7 @@ namespace iter { //specializations for initializer_lists template - auto filterfalse(FilterFunc filter_func, std::initializer_list && container) -> + auto filterfalse(FilterFunc filter_func, std::initializer_list&& container) -> decltype(filter( detail::PredicateFlipper>( filter_func), @@ -87,7 +87,7 @@ namespace iter { // Single argument version, uses a BoolFlipper to reverse the truthiness // of an object template - auto filterfalse(std::initializer_list && container) -> + auto filterfalse(std::initializer_list&& container) -> decltype(filter( detail::BoolFlipper>(), std::move(container))) { From f8e51d05cb262141ed503a49bf224c8e02847c3f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 12:48:32 -0700 Subject: [PATCH 0318/1866] formats accumulate --- accumulate.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index 0e07bf47..792a27aa 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -73,7 +73,7 @@ namespace iter { return this->acc_val; } - Iterator & operator++() { + Iterator& operator++() { ++this->sub_iter; if (this->sub_iter != this->sub_end) { this->acc_val = accumulate_func( @@ -82,7 +82,7 @@ namespace iter { return *this; } - bool operator!=(const Iterator & other) const { + bool operator!=(const Iterator& other) const { return this->sub_iter != other.sub_iter; } }; From c140d44a80f74746bb2714d073b25e32513bf100 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 12:48:46 -0700 Subject: [PATCH 0319/1866] formats compress.hpp --- compress.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compress.hpp b/compress.hpp index b18d7d0b..34aa22cf 100644 --- a/compress.hpp +++ b/compress.hpp @@ -103,13 +103,13 @@ namespace iter { return *this->sub_iter; } - Iterator & operator++() { + Iterator& operator++() { this->increment_iterators(); this->skip_failures(); return *this; } - bool operator!=(const Iterator & other) const { + bool operator!=(const Iterator& other) const { return this->sub_iter != other.sub_iter && this->selector_iter != other.selector_iter; } From 1c60e66e4f8e78cb98cc0edf7690be8a11b2f75d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 12:49:01 -0700 Subject: [PATCH 0320/1866] formats cycle --- cycle.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cycle.hpp b/cycle.hpp index 13c4b1f0..7dc76424 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -55,7 +55,7 @@ namespace iter { return *this->sub_iter; } - Iterator & operator++() { + Iterator& operator++() { ++this->sub_iter; // reset to beginning upon reaching the end if (!(this->sub_iter != this->end)) { @@ -68,7 +68,7 @@ namespace iter { return *this; } - constexpr bool operator!=(const Iterator &) const { + constexpr bool operator!=(const Iterator&) const { return true; } }; From 30cf448b1889ca025e896e84854324f66f00e12c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 12:49:17 -0700 Subject: [PATCH 0321/1866] formats dropwhile --- dropwhile.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index 0393845e..724f0122 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -72,12 +72,12 @@ namespace iter { return *this->sub_iter; } - Iterator & operator++() { + Iterator& operator++() { ++this->sub_iter; return *this; } - bool operator!=(const Iterator & other) const { + bool operator!=(const Iterator& other) const { return this->sub_iter != other.sub_iter; } }; From bcd74f84cdb819d71dac5ade32bee0fdca39f564 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 12:49:25 -0700 Subject: [PATCH 0322/1866] formats enumerate --- enumerate.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 849c7533..6ff3faae 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -80,13 +80,13 @@ namespace iter { return IterYield(this->index, *this->sub_iter); } - Iterator & operator++() { + Iterator& operator++() { ++this->sub_iter; ++this->index; return *this; } - bool operator!=(const Iterator & other) const { + bool operator!=(const Iterator& other) const { return this->sub_iter != other.sub_iter; } }; From 53756ab579e9f93ba19c822b5abd2083d831675d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 12:49:58 -0700 Subject: [PATCH 0323/1866] formats filter --- filter.hpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/filter.hpp b/filter.hpp index 143cc9e8..f6695d44 100644 --- a/filter.hpp +++ b/filter.hpp @@ -14,36 +14,36 @@ namespace iter { class Filter; template - Filter filter(FilterFunc, Container &&); + Filter filter(FilterFunc, Container&&); template Filter> filter( - FilterFunc, std::initializer_list &&); + FilterFunc, std::initializer_list&&); template class Filter { private: - Container & container; + Container& container; FilterFunc filter_func; // The filter function is the only thing allowed to create a Filter friend Filter filter( - FilterFunc, Container &&); + FilterFunc, Container&&); template friend Filter> filter( - FF, std::initializer_list &&); + FF, std::initializer_list&&); // Value constructor for use only in the filter function - Filter(FilterFunc filter_func, Container && container) + Filter(FilterFunc filter_func, Container&& container) : container{container}, filter_func(filter_func) { } - Filter () = delete; - Filter & operator=(const Filter &) = delete; + Filter() = delete; + Filter& operator=(const Filter&) = delete; public: - Filter(const Filter &) = default; + Filter(const Filter&) = default; class Iterator { protected: @@ -75,13 +75,13 @@ namespace iter { return *this->sub_iter; } - Iterator & operator++() { + Iterator& operator++() { ++this->sub_iter; this->skip_failures(); return *this; } - bool operator!=(const Iterator & other) const { + bool operator!=(const Iterator& other) const { return this->sub_iter != other.sub_iter; } }; @@ -103,14 +103,14 @@ namespace iter { // Helper function to instantiate a Filter template Filter filter( - FilterFunc filter_func, Container && container) { + FilterFunc filter_func, Container&& container) { return {filter_func, std::forward(container)}; } template Filter> filter( FilterFunc filter_func, - std::initializer_list && il) + std::initializer_list&& il) { return {filter_func, std::move(il)}; } @@ -118,7 +118,7 @@ namespace iter { namespace detail { template - bool boolean_cast(const T & t) { + bool boolean_cast(const T& t) { return bool(t); } @@ -133,7 +133,7 @@ namespace iter { template - auto filter(Container && container) -> + auto filter(Container&& container) -> decltype(filter( detail::BoolTester(), std::forward(container))) { @@ -143,7 +143,7 @@ namespace iter { } template - auto filter(std::initializer_list && il) -> + auto filter(std::initializer_list&& il) -> decltype(filter( detail::BoolTester>(), std::move(il))) { From d0b4c03f95af6c3c2a51d669842a385dd3905756 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 12:55:02 -0700 Subject: [PATCH 0324/1866] formats groupby --- groupby.hpp | 60 ++++++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index c4868897..8c63f0f4 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -13,23 +13,23 @@ namespace iter { class GroupBy; template - GroupBy groupby(Container &&, KeyFunc); + GroupBy groupby(Container&&, KeyFunc); template GroupBy, KeyFunc> groupby( - std::initializer_list &&, KeyFunc); + std::initializer_list&&, KeyFunc); template class GroupBy { private: - Container & container; + Container& container; KeyFunc key_func; - friend GroupBy groupby(Container &&, KeyFunc); + friend GroupBy groupby(Container&&, KeyFunc); template friend GroupBy, KF> groupby( - std::initializer_list &&, KF); + std::initializer_list&&, KF); @@ -39,18 +39,18 @@ namespace iter { decltype(std::declval()( std::declval>())); - GroupBy(Container && container, KeyFunc key_func) + GroupBy(Container&& container, KeyFunc key_func) : container{container}, key_func(key_func) { } public: - GroupBy () = delete; - GroupBy(const GroupBy &) = delete; - GroupBy& operator=(const GroupBy &) = delete; + GroupBy() = delete; + GroupBy(const GroupBy&) = delete; + GroupBy& operator=(const GroupBy&) = delete; - GroupBy (GroupBy &&) = default; - GroupBy & operator=(GroupBy &&) = default; + GroupBy(GroupBy&&) = default; + GroupBy& operator=(GroupBy&&) = default; class Iterator; class Group; @@ -82,11 +82,11 @@ namespace iter { this->key_func(*this->sub_iter))); } - Iterator & operator++() { + Iterator& operator++() { return *this; } - bool operator!=(const Iterator &) const { + bool operator!=(const Iterator&) const { return !this->exhausted(); } @@ -114,7 +114,7 @@ namespace iter { private: friend Iterator; friend class GroupIterator; - Iterator & owner; + Iterator& owner; key_func_ret key; // completed is set if a Group is iterated through @@ -128,7 +128,7 @@ namespace iter { // when called. mutable bool completed = false; - Group(Iterator & owner, key_func_ret key) : + Group(Iterator& owner, key_func_ret key) : owner(owner), key(key) { } @@ -143,12 +143,12 @@ namespace iter { } // movable, non-copyable - Group () = delete; - Group (const Group &) = delete; - Group & operator=(const Group &) = delete; + Group() = delete; + Group(const Group&) = delete; + Group& operator=(const Group&) = delete; - Group & operator=(Group &&) = default; - Group (Group && other) + Group& operator=(Group&&) = default; + Group(Group&& other) : owner{other.owner}, key{other.key}, completed{other.completed} { @@ -158,23 +158,23 @@ namespace iter { class GroupIterator { private: const key_func_ret key; - const Group & group; + const Group& group; bool not_at_end() const { - return !this->group.owner.exhausted() && + return !this->group.owner.exhausted()&& this->group.owner.next_key() == this->key; } public: - GroupIterator(const Group & group, + GroupIterator(const Group& group, key_func_ret key) : key{key}, group{group} { } - GroupIterator(const GroupIterator &) = default; + GroupIterator(const GroupIterator&) = default; - bool operator!=(const GroupIterator &) const { + bool operator!=(const GroupIterator&) const { if (this->not_at_end()) { return true; } else { @@ -183,7 +183,7 @@ namespace iter { } } - GroupIterator & operator++() { + GroupIterator& operator++() { this->group.owner.increment_iterator(); return *this; } @@ -233,13 +233,13 @@ namespace iter { template GroupBy groupby( - Container && container, KeyFunc key_func) { + Container&& container, KeyFunc key_func) { return {std::forward(container), key_func}; } template - auto groupby(Container && container) -> + auto groupby(Container&& container) -> decltype(groupby(std::forward(container), ItemReturner())) { return groupby(std::forward(container), @@ -249,13 +249,13 @@ namespace iter { template GroupBy, KeyFunc> groupby( - std::initializer_list && il, KeyFunc key_func) { + std::initializer_list&& il, KeyFunc key_func) { return {std::move(il), key_func}; } template - auto groupby(std::initializer_list && il) -> + auto groupby(std::initializer_list&& il) -> decltype(groupby(std::move(il), ItemReturner>())) { return groupby( From 8378aa2183b9a466b848c6e460433b03159211d9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 13:01:02 -0700 Subject: [PATCH 0325/1866] Removes move assignment from GroupBy --- groupby.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index 8c63f0f4..39cce2f8 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -48,9 +48,9 @@ namespace iter { GroupBy() = delete; GroupBy(const GroupBy&) = delete; GroupBy& operator=(const GroupBy&) = delete; + GroupBy& operator=(GroupBy&&) = delete; GroupBy(GroupBy&&) = default; - GroupBy& operator=(GroupBy&&) = default; class Iterator; class Group; @@ -146,8 +146,8 @@ namespace iter { Group() = delete; Group(const Group&) = delete; Group& operator=(const Group&) = delete; + Group& operator=(Group&&) = delete; - Group& operator=(Group&&) = default; Group(Group&& other) : owner{other.owner}, key{other.key}, From 33d5c6dcaf83d1b5ea120e9aa99b36b79571786a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 13:03:17 -0700 Subject: [PATCH 0326/1866] formats imap --- imap.hpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/imap.hpp b/imap.hpp index 6eeaaae8..40003417 100644 --- a/imap.hpp +++ b/imap.hpp @@ -18,7 +18,7 @@ namespace iter { template struct call_impl { - static auto call(F f, Tuple && t) -> + static auto call(F f, Tuple&& t) -> decltype(call_impl struct call_impl { - static auto call(F f, Tuple && t) -> + static auto call(F f, Tuple&& t) -> decltype(f(std::get(std::forward(t))...)) { return f(std::get(std::forward(t))...); @@ -47,7 +47,7 @@ namespace iter { // user invokes this template - auto call(F f, Tuple && t) -> + auto call(F f, Tuple&& t) -> decltype(call_impl::type>::value, @@ -67,12 +67,12 @@ namespace iter { class IMap; template - IMap imap(MapFunc, Containers &&...); + IMap imap(MapFunc, Containers&&...); template class IMap { // The imap function is the only thing allowed to create a IMap - friend IMap imap(MapFunc, Containers && ...); + friend IMap imap(MapFunc, Containers&& ...); // The type returned when dereferencing the Containers...::Iterator // XXX depends on zip using iterator_range. would be nice if it didn't @@ -87,15 +87,15 @@ namespace iter { Zipped zipped; // Value constructor for use only in the imap function - IMap(MapFunc map_func, Containers && ... containers) : + IMap(MapFunc map_func, Containers&& ... containers) : map_func(map_func), zipped(zip(std::forward(containers)...)) { } - IMap () = delete; - IMap & operator=(const IMap &) = delete; + IMap() = delete; + IMap& operator=(const IMap&) = delete; public: - IMap (const IMap &) = default; + IMap(const IMap&) = default; class Iterator { private: @@ -114,12 +114,12 @@ namespace iter { return detail::call(this->map_func, *(this->zipiter)); } - Iterator & operator++() { + Iterator& operator++() { ++this->zipiter; return *this; } - bool operator!=(const Iterator & other) const { + bool operator!=(const Iterator& other) const { return this->zipiter != other.zipiter; } }; @@ -137,7 +137,7 @@ namespace iter { // Helper function to instantiate a IMap template IMap imap( - MapFunc map_func, Containers && ... containers) { + MapFunc map_func, Containers&& ... containers) { return {map_func, std::forward(containers)...}; } From 24192e769096401eefb30f54be192e2025404e2d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 13:04:28 -0700 Subject: [PATCH 0327/1866] formats range --- range.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/range.hpp b/range.hpp index 28d3e6a7..5359379c 100644 --- a/range.hpp +++ b/range.hpp @@ -62,7 +62,7 @@ namespace iter { public: Range() = delete; - Range(const Range &) = default; + Range(const Range&) = default; class Iterator { private: T value; @@ -90,7 +90,7 @@ namespace iter { return this->value; } - Iterator & operator++() { + Iterator& operator++() { this->value += this->step; return *this; } @@ -108,7 +108,7 @@ namespace iter { // 2) (stop - start) % step != 0. For // example Range(1, 10, 2). The iterator will never be // exactly equal to the stop value. - bool operator!=(const Iterator & other) const { + bool operator!=(const Iterator& other) const { return not_equal_to( other, typename std::is_unsigned::type()); } From d4a7bc827164a48ab9bb346c192534dadb21dea3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 13:05:45 -0700 Subject: [PATCH 0328/1866] formats sorted --- sorted.hpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sorted.hpp b/sorted.hpp index ce824541..15d36b22 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -12,22 +12,22 @@ namespace iter { class Sorted; template - Sorted sorted(Container &, CompareFunc); + Sorted sorted(Container&, CompareFunc); template class Sorted { private: friend Sorted - sorted(Container &, CompareFunc); + sorted(Container&, CompareFunc); std::vector> sorted_iters; using sorted_iter_type = decltype(std::begin(sorted_iters)); Sorted() = delete; - Sorted & operator=(const Sorted &) = delete; + Sorted& operator=(const Sorted&) = delete; - Sorted(Container & container, CompareFunc compare_func) { + Sorted(Container& container, CompareFunc compare_func) { // Fill the sorted_iters vector with an iterator to each // element in the container for (auto iter = std::begin(container); @@ -38,14 +38,14 @@ namespace iter { // sort by comparing the elements that the iterators point to std::sort(std::begin(sorted_iters), std::end(sorted_iters), - [&] (const iterator_type & it1, - const iterator_type & it2) + [&] (const iterator_type& it1, + const iterator_type& it2) { return compare_func(*it1, *it2); }); } public: - Sorted(const Sorted &) = default; + Sorted(const Sorted&) = default; // Iterates over a series of Iterators, automatically dereferencing // them when accessed with operator * @@ -54,7 +54,7 @@ namespace iter { IteratorIterator(sorted_iter_type iter) : sorted_iter_type{iter} { } - IteratorIterator(const IteratorIterator &) = default; + IteratorIterator(const IteratorIterator&) = default; // Dereference the current iterator before returning iterator_deref operator*() { @@ -74,12 +74,12 @@ namespace iter { template Sorted sorted( - Container & container, CompareFunc compare_func) { + Container& container, CompareFunc compare_func) { return {container, compare_func}; } template - auto sorted(Container & container) -> + auto sorted(Container& container) -> decltype(sorted( container, std::less Date: Mon, 26 May 2014 13:06:37 -0700 Subject: [PATCH 0329/1866] formats takewhile --- takewhile.hpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/takewhile.hpp b/takewhile.hpp index 92937e20..d534b2f2 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -14,36 +14,36 @@ namespace iter { class TakeWhile; template - TakeWhile takewhile(FilterFunc, Container &&); + TakeWhile takewhile(FilterFunc, Container&&); template TakeWhile> takewhile( - FilterFunc, std::initializer_list &&); + FilterFunc, std::initializer_list&&); template class TakeWhile { private: - Container & container; + Container& container; FilterFunc filter_func; friend TakeWhile takewhile( - FilterFunc, Container &&); + FilterFunc, Container&&); template friend TakeWhile> takewhile( - FF, std::initializer_list &&); + FF, std::initializer_list&&); // Value constructor for use only in the takewhile function - TakeWhile(FilterFunc filter_func, Container && container) + TakeWhile(FilterFunc filter_func, Container&& container) : container{container}, filter_func(filter_func) { } TakeWhile () = delete; - TakeWhile & operator=(const TakeWhile &) = delete; + TakeWhile& operator=(const TakeWhile&) = delete; public: - TakeWhile(const TakeWhile &) = default; + TakeWhile(const TakeWhile&) = default; class Iterator { private: @@ -82,13 +82,13 @@ namespace iter { return *this->sub_iter; } - Iterator & operator++() { + Iterator& operator++() { ++this->sub_iter; this->check_current(); return *this; } - bool operator!=(const Iterator & other) const { + bool operator!=(const Iterator& other) const { return this->sub_iter != other.sub_iter; } }; @@ -110,13 +110,13 @@ namespace iter { // Helper function to instantiate a TakeWhile template TakeWhile takewhile( - FilterFunc filter_func, Container && container) { + FilterFunc filter_func, Container&& container) { return {filter_func, std::forward(container)}; } template TakeWhile> takewhile( - FilterFunc filter_func, std::initializer_list && il) + FilterFunc filter_func, std::initializer_list&& il) { return {filter_func, std::move(il)}; } From 0321946b0081ffff7375290d13df9d94771e1abc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 14:41:54 -0700 Subject: [PATCH 0330/1866] replaces .begin and .end with std::begin/std::end there were a couple still in there preventing static sized array compatibility --- zip.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zip.hpp b/zip.hpp index 200a9328..351135d0 100644 --- a/zip.hpp +++ b/zip.hpp @@ -15,10 +15,10 @@ namespace iter { iterator_range> { auto begin = - zip_iter(std::begin(containers)...); + zip_iter(std::begin(containers)...); auto end = - zip_iter(std::end(containers)...); + zip_iter(std::end(containers)...); return iterator_range(begin,end); } From 2baae9fbe85eef3c99ba21eb97c816490c740bb1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 15:00:43 -0700 Subject: [PATCH 0331/1866] uniform initialization update --- zip.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zip.hpp b/zip.hpp index 351135d0..2ef13689 100644 --- a/zip.hpp +++ b/zip.hpp @@ -20,7 +20,7 @@ namespace iter { auto end = zip_iter(std::end(containers)...); - return iterator_range(begin,end); + return {begin,end}; } From 532a764a479c54fd897df049cf353040dc23a3c6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 19:27:53 -0700 Subject: [PATCH 0332/1866] Incomplete, alternative zip implementation Works with everything except the last testcase in testzip. The last zip causes a seg fault. --- zip.hpp | 194 +++++++++++++++++++++++++++----------------------------- 1 file changed, 94 insertions(+), 100 deletions(-) diff --git a/zip.hpp b/zip.hpp index 2ef13689..610e12a4 100644 --- a/zip.hpp +++ b/zip.hpp @@ -1,119 +1,113 @@ -#ifndef ZIP_HPP -#define ZIP_HPP +#include "iterbase.hpp" -#include "iterator_range.hpp" - -#include #include +#include +#include namespace iter { - template - class zip_iter; - - template - auto zip(Containers && ... containers) -> - iterator_range> - { - auto begin = - zip_iter(std::begin(containers)...); - - auto end = - zip_iter(std::end(containers)...); - - return {begin,end}; - } - - - template - class zip_iter { + template + class Zipped { private: - Iterator iter; - + Container& container; + Zipped rest_zipped; public: - using elem_type = decltype(*iter); - zip_iter(const Iterator & i) : - iter(i){ } - - auto operator*() -> decltype(std::forward_as_tuple(*iter)) - { - return std::forward_as_tuple(*iter); - } - zip_iter & operator++() { - ++iter; - return *this; + Zipped(Container&& container, RestContainers&&... rest) + : container{container}, + rest_zipped{std::forward(rest)...} + { } + + class Iterator { + private: + using RestIter = + typename Zipped::Iterator; + + iterator_type iter; + RestIter rest_iter; + public: + Iterator(iterator_type it, const RestIter& rest) + : iter{it}, + rest_iter{rest} + { } + + Iterator& operator++() { + ++this->iter; + ++this->rest_iter; + return *this; + } + + bool operator!=(const Iterator& other) const { + return this->iter != other.iter && + this->rest_iter != other.rest_iter; + } + + auto operator*() -> + decltype(std::tuple_cat(std::make_tuple( + *this->iter), *this->rest_iter)) + { + return std::tuple_cat(std::make_tuple( + *this->iter), *this->rest_iter); + } + }; + + Iterator begin() const { + return {std::begin(this->container), + std::begin(this->rest_zipped)}; } - bool operator!=(const zip_iter & rhs) const { - return (this->iter != rhs.iter); + + Iterator end() const { + return {std::end(this->container), + std::end(this->rest_zipped)}; } }; -#if 0 - template - struct zip_iter { - private: - First iter1; - Second iter2; - public: - using Elem1_t = decltype(*iter1); - using Elem2_t = decltype(*iter2); - zip_iter(const First & f, const Second & s) : - iter1(f),iter2(s) { } - - auto operator*() -> decltype(std::forward_as_tuple(*iter1,*iter2)) - { - return std::forward_as_tuple(*iter1,*iter2); - } - zip_iter & operator++() { - ++iter1; - ++iter2; - return *this; - } - bool operator!=(const zip_iter & rhs) const { - return (this->iter1 != rhs.iter1) && (this->iter2 != rhs.iter2); - } - }; -#endif - //this specialization commented out - template - class zip_iter { + template + class Zipped { private: - First iter; - zip_iter inner_iter; - + Container& container; public: - using elem_type = decltype(*iter); - using tuple_type = - decltype(std::tuple_cat(std::forward_as_tuple(*iter),*inner_iter)); - - zip_iter(const First & f, const Rest & ... rest) : - iter(f), - inner_iter(rest...) {} - - - tuple_type operator*() - { - return std::tuple_cat(std::forward_as_tuple(*iter),*inner_iter); - } - - zip_iter & operator++() { - ++iter; - ++inner_iter; - return *this; + Zipped(Container&& container) + : container{container} + { } + + class Iterator { + private: + iterator_type iter; + public: + Iterator(iterator_type it) + : iter{it} + { } + + Iterator& operator++() { + ++this->iter; + return *this; + } + + bool operator!=(const Iterator& other) const { + // if this->iter == other.iter, then won't every other + // level have to be the same? + // in other words, I should only have to compare iter, + // and not rest as well + return this->iter != other.iter; + } + + auto operator*() -> decltype(std::make_tuple(*this->iter)) + { + return std::make_tuple(*this->iter); + } + }; + + Iterator begin() const { + return {std::begin(this->container)}; } - bool operator!=(const zip_iter & rhs) const { - return (this->iter != rhs.iter) && - (this->inner_iter != rhs.inner_iter); + Iterator end() const { + return {std::end(this->container)}; } }; -} -namespace std { - template - struct iterator_traits> { - using difference_type = ptrdiff_t; - using iterator_category = input_iterator_tag; - }; + template + Zipped zip(Containers&&... containers) { + return {std::forward(containers)...}; + } } -#endif //ZIP_HPP From 5a16f79e3b4e0da6a372b5a28efb2ec6f165b1c8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 19:32:09 -0700 Subject: [PATCH 0333/1866] adds zip test with statically sized array --- tests/testzip.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/testzip.cpp b/tests/testzip.cpp index 65254030..66e5eda5 100644 --- a/tests/testzip.cpp +++ b/tests/testzip.cpp @@ -21,7 +21,6 @@ int main() { i = 69; std::cout << std::get<1>(e) << std::endl; } - for (auto e : zip(ivec, svec)) { std::cout << std::get<0>(e) << std::endl; std::cout << std::get<1>(e) << std::endl; @@ -31,6 +30,13 @@ int main() { 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 { @@ -89,8 +95,6 @@ int main() { } - - return 0; } From d63c17ba87cec35a4d555665ed996ca021d976af Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 19:35:39 -0700 Subject: [PATCH 0334/1866] formats the last test in testzip --- tests/testzip.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/testzip.cpp b/tests/testzip.cpp index 66e5eda5..ed8066ec 100644 --- a/tests/testzip.cpp +++ b/tests/testzip.cpp @@ -83,8 +83,11 @@ int main() { } std::cout< constvector{1.1,2.2,3.3,4.4}; - for (auto e : zip(iter::chain(std::vector(5,5),std::array{{1,2}}), - std::initializer_list{"asdfas","aaron","ryan","apple","juice"}, + for (auto e : zip( + iter::chain(std::vector(5,5), + std::array{{1,2}}), + std::initializer_list{ + "asdfas","aaron","ryan","apple","juice"}, constvector)) { From 20bcf7f7f7d62c20bea1a9e306b12b618b73ccf5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 May 2014 22:12:23 -0700 Subject: [PATCH 0335/1866] Makes imap compatible with new zip (much nicer) The old version relied on an implentation detail of zip and (at the time at least) I couldn't get rid of that reliance. The use of the new zip is oblivious to the implementation. This rules. --- imap.hpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/imap.hpp b/imap.hpp index 40003417..42fba58b 100644 --- a/imap.hpp +++ b/imap.hpp @@ -74,17 +74,10 @@ namespace iter { // The imap function is the only thing allowed to create a IMap friend IMap imap(MapFunc, Containers&& ...); - // The type returned when dereferencing the Containers...::Iterator - // XXX depends on zip using iterator_range. would be nice if it didn't - using Zipped = - iterator_range().begin())...>>; - - using ZippedIterType = decltype(std::declval().begin()); - //typename std::remove_const().begin())>::type; - + using ZippedIterType = iterator_type>; private: MapFunc map_func; - Zipped zipped; + Zipped zipped; // Value constructor for use only in the imap function IMap(MapFunc map_func, Containers&& ... containers) : @@ -103,7 +96,7 @@ namespace iter { mutable ZippedIterType zipiter; public: - Iterator (MapFunc map_func, ZippedIterType zipiter) : + Iterator(MapFunc map_func, ZippedIterType zipiter) : map_func(map_func), zipiter(zipiter) { } From cd88f0e60a04da1cdba4b4fbac2afe6e4b430a34 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 28 May 2014 23:18:28 -0700 Subject: [PATCH 0336/1866] Safe support for temporaries in enumerate I will need to add this to everything soon. This works by adding an overload to the enumerate() function. If an lvalue is passed, the Enumerable binds an lvalue to it. If an rvalue is passed, the Enumerable move constructs it. It's easier explained in the code. Also, must make the value constructor private again to complete this --- enumerate.hpp | 50 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 6ff3faae..aa620daf 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -20,6 +20,7 @@ namespace iter { +#if 0 //Forward declarations of Enumerable and enumerate template class Enumerable; @@ -29,27 +30,37 @@ namespace iter { template Enumerable enumerate(Container&&); +#endif template class Enumerable { - private: - Container& container; + //private: + public: + Container container; +#if 0 // The only thing allowed to directly instantiate an Enumerable is // the enumerate function - friend Enumerable enumerate(Container&&); + friend Enumerable enumerate(Container); template friend Enumerable> enumerate( std::initializer_list&&); - - Enumerable(Container&& container) : container{container} { } +#endif + + Enumerable(Container container) + : container(std::forward(container)) + { } public: // Value constructor for use only in the enumerate function - Enumerable () = delete; - Enumerable & operator=(const Enumerable&) = delete; + Enumerable() = delete; + Enumerable& operator=(const Enumerable&) = delete; + Enumerable(const Enumerable&) = delete; + Enumerable& operator=(Enumerable&&) = delete; - Enumerable(const Enumerable&) = default; + // movable only + Enumerable(Enumerable&&) = default; + ~Enumerable() = default; // "yielded" by the Enumerable::Iterator. Has a .index, and a // .element referencing the value yielded by the subiterator @@ -91,27 +102,38 @@ namespace iter { } }; - Iterator begin() const { + Iterator begin() { return {std::begin(this->container)}; } - Iterator end() const { + Iterator end() { return {std::end(this->container)}; } }; - // Helper function to instantiate an Enumerable + // any lvalues passed will go here, instantiating Enumerabe + // this will result in enumerate iterating over a reference to the + // provided value, as is the usual intention + template + Enumerable enumerate(Container& container) { + return {container}; + } + + // any rvalue passed will go here, instantiating Enumerabel + // instead of binding a reference, the Enumerable ctor will move construct + // the temporary `container` as a data member template Enumerable enumerate(Container&& container) { - return {std::forward(container)}; + return {std::move(container)}; } + // for initializer lists. copy constructs the list into the Enumerable template Enumerable> enumerate( - std::initializer_list&& il) + std::initializer_list il) { - return {std::move(il)}; + return {il}; } } From 8f525b202fda4d35f3e346ce06e3c005f958b2bc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 28 May 2014 23:28:49 -0700 Subject: [PATCH 0337/1866] Restores privacy to enumerate --- enumerate.hpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index aa620daf..bda03e78 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -20,32 +20,33 @@ namespace iter { -#if 0 //Forward declarations of Enumerable and enumerate template class Enumerable; - template - Enumerable> enumerate(std::initializer_list&&); + template + Enumerable enumerate(Container&); template Enumerable enumerate(Container&&); -#endif + + template + Enumerable> enumerate(std::initializer_list); template class Enumerable { - //private: - public: + private: Container container; -#if 0 // The only thing allowed to directly instantiate an Enumerable is // the enumerate function - friend Enumerable enumerate(Container); + template + friend Enumerable enumerate(C&); + template + friend Enumerable enumerate(C&&); template friend Enumerable> enumerate( - std::initializer_list&&); -#endif + std::initializer_list); Enumerable(Container container) : container(std::forward(container)) From 2464b19be70f8b704094cdde5cfbbeb5ad511591 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 28 May 2014 23:40:59 -0700 Subject: [PATCH 0338/1866] adds missing include guards to zip --- zip.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/zip.hpp b/zip.hpp index 610e12a4..a57e5b73 100644 --- a/zip.hpp +++ b/zip.hpp @@ -1,3 +1,6 @@ +#ifndef ZIP__H__ +#define ZIP__H__ + #include "iterbase.hpp" #include @@ -111,3 +114,5 @@ namespace iter { return {std::forward(containers)...}; } } + +#endif //#ifndef ZIP__H__ From 43d455dfe972216f02490aab1afac0cce107b8ae Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 30 May 2014 22:22:31 -0700 Subject: [PATCH 0339/1866] Uses alternative scheme for supporting temps this seems easier implemented. If the argument to enumerate() is an lvalue then Enumerable is templated on an lvalue reference type (just because of how universal references work). Otherwise it gets templated on a non-reference type. the std::forward in the constructor results in a move construction when templated on a non-reference type, and an lvalue reference bind when it is a reference type. --- enumerate.hpp | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index bda03e78..aa961fd8 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -7,6 +7,7 @@ #include #include #include +#include // enumerate functionality for python-style for-each enumerate loops @@ -24,9 +25,6 @@ namespace iter { template class Enumerable; - template - Enumerable enumerate(Container&); - template Enumerable enumerate(Container&&); @@ -35,19 +33,23 @@ namespace iter { template class Enumerable { + static_assert(!std::is_rvalue_reference::value, + "Itertools cannot be templated with rvalue references"); private: Container container; + // lvalue ref if it's an lvalue, non-ref type otherwise // The only thing allowed to directly instantiate an Enumerable is // the enumerate function - template - friend Enumerable enumerate(C&); - template - friend Enumerable enumerate(C&&); + friend Enumerable enumerate(Container&&); template friend Enumerable> enumerate( std::initializer_list); - + + // FIXME it seems like if an rvalue is passed, Container will + // not be a reference type at all, which will cause this to copy + // construct rather than move construct. But somehow that doesn't + // happen and it gets move constructed. Must investigate further Enumerable(Container container) : container(std::forward(container)) { } @@ -113,30 +115,18 @@ namespace iter { }; - // any lvalues passed will go here, instantiating Enumerabe - // this will result in enumerate iterating over a reference to the - // provided value, as is the usual intention - template - Enumerable enumerate(Container& container) { - return {container}; - } - - // any rvalue passed will go here, instantiating Enumerabel - // instead of binding a reference, the Enumerable ctor will move construct - // the temporary `container` as a data member template Enumerable enumerate(Container&& container) { - return {std::move(container)}; + return {std::forward(container)}; } // for initializer lists. copy constructs the list into the Enumerable template Enumerable> enumerate( std::initializer_list il) - { + { return {il}; } - } #endif //ifndef ENUMERABLE__H__ From 5b939c291b02413aa1d0ae1c8b31861149fd220a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 30 May 2014 22:25:46 -0700 Subject: [PATCH 0340/1866] Adds true temporary support to zip --- zip.hpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/zip.hpp b/zip.hpp index 610e12a4..df54ed36 100644 --- a/zip.hpp +++ b/zip.hpp @@ -7,12 +7,14 @@ namespace iter { template class Zipped { + static_assert(!std::is_rvalue_reference::value, + "Itertools cannot be templated with rvalue references"); private: - Container& container; + Container container; Zipped rest_zipped; public: - Zipped(Container&& container, RestContainers&&... rest) - : container{container}, + Zipped(Container container, RestContainers&&... rest) + : container(std::forward(container)), rest_zipped{std::forward(rest)...} { } @@ -49,12 +51,12 @@ namespace iter { } }; - Iterator begin() const { + Iterator begin() { return {std::begin(this->container), std::begin(this->rest_zipped)}; } - Iterator end() const { + Iterator end() { return {std::end(this->container), std::end(this->rest_zipped)}; } @@ -63,11 +65,13 @@ namespace iter { template class Zipped { + static_assert(!std::is_rvalue_reference::value, + "Itertools cannot be templated with rvalue references"); private: - Container& container; + Container container; public: - Zipped(Container&& container) - : container{container} + Zipped(Container container) + : container(std::forward(container)) { } class Iterator { @@ -97,11 +101,11 @@ namespace iter { } }; - Iterator begin() const { + Iterator begin() { return {std::begin(this->container)}; } - Iterator end() const { + Iterator end() { return {std::end(this->container)}; } }; From 186592ed18ae37a9aeb87ef6c77641bfa133a94d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 30 May 2014 22:34:53 -0700 Subject: [PATCH 0341/1866] Makes Zipped constrctor private and zip a friend --- zip.hpp | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/zip.hpp b/zip.hpp index df54ed36..2922c64e 100644 --- a/zip.hpp +++ b/zip.hpp @@ -4,20 +4,34 @@ #include #include + namespace iter { + template + class Zipped; + + template + Zipped zip(Containers&&...); + 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; + private: Container container; Zipped rest_zipped; - public: Zipped(Container container, RestContainers&&... rest) : container(std::forward(container)), rest_zipped{std::forward(rest)...} { } + public: class Iterator { private: using RestIter = @@ -67,13 +81,20 @@ namespace iter { class Zipped { static_assert(!std::is_rvalue_reference::value, "Itertools cannot be templated with rvalue references"); + + friend Zipped zip(Container&&); + + template + friend class Zipped; + private: Container container; - public: Zipped(Container container) : container(std::forward(container)) { } + public: + class Iterator { private: iterator_type iter; From cb7e9dc20e5896eeb7d55eaa728f2f0a26af8718 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 May 2014 23:08:20 -0700 Subject: [PATCH 0342/1866] Fixes zip so one can modify data while iterating I was using std::make_tuple to get the type of the value in the tuple, but I neglected to realize this would cause it to drop the reference part of the type. By explicitly giving it std::tuple> this is avoided. If the iterator derefences to a reference type, the tuple will hold a reference. --- zip.hpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/zip.hpp b/zip.hpp index 2922c64e..f8fab45b 100644 --- a/zip.hpp +++ b/zip.hpp @@ -57,11 +57,15 @@ namespace iter { } auto operator*() -> - decltype(std::tuple_cat(std::make_tuple( - *this->iter), *this->rest_iter)) + decltype(std::tuple_cat( + std::tuple>{ + *this->iter}, + *this->rest_iter)) { - return std::tuple_cat(std::make_tuple( - *this->iter), *this->rest_iter); + return std::tuple_cat( + std::tuple>{ + *this->iter}, + *this->rest_iter); } }; @@ -109,16 +113,12 @@ namespace iter { } bool operator!=(const Iterator& other) const { - // if this->iter == other.iter, then won't every other - // level have to be the same? - // in other words, I should only have to compare iter, - // and not rest as well return this->iter != other.iter; } - auto operator*() -> decltype(std::make_tuple(*this->iter)) - { - return std::make_tuple(*this->iter); + std::tuple> operator*() { + return std::tuple>{ + *this->iter}; } }; From f32a2e5bd739cae56d807519c93317163d2eadbd Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 May 2014 23:15:38 -0700 Subject: [PATCH 0343/1866] More intense testzip better test for temporaries. asserts to make sure the value of the vector was changed after iterating. --- tests/testzip.cpp | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/tests/testzip.cpp b/tests/testzip.cpp index ed8066ec..3003bc40 100644 --- a/tests/testzip.cpp +++ b/tests/testzip.cpp @@ -6,6 +6,7 @@ #include #include #include +#include using iter::zip; @@ -15,17 +16,27 @@ int main() { 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 = 69; + 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'; @@ -84,16 +95,19 @@ int main() { std::cout< constvector{1.1,2.2,3.3,4.4}; for (auto e : zip( - iter::chain(std::vector(5,5), - std::array{{1,2}}), - std::initializer_list{ - "asdfas","aaron","ryan","apple","juice"}, + // the chain test breaks it, but its chain's fault + //iter::chain(std::vector(5,5), + // 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) << std::endl; + << std::get<1>(e) << " " + //<< std::get<2>(e) + << '\n'; } } From dc821d0d71b574f40b5d9f470062c968d22b642a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 May 2014 23:17:23 -0700 Subject: [PATCH 0344/1866] Adds enumerate test with temporaries --- tests/testenumerate.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/testenumerate.cpp b/tests/testenumerate.cpp index 498139e3..cd41bc90 100644 --- a/tests/testenumerate.cpp +++ b/tests/testenumerate.cpp @@ -1,3 +1,5 @@ +#include "testbase.hpp" + #include #include @@ -36,17 +38,25 @@ int main() { 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; } From f4b7069b411b7ef99f94cb1ba4e2da70f487f250 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 09:08:53 -0700 Subject: [PATCH 0345/1866] removes old comments --- enumerate.hpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index aa961fd8..f2e63ff2 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -38,7 +38,6 @@ namespace iter { private: Container container; - // lvalue ref if it's an lvalue, non-ref type otherwise // The only thing allowed to directly instantiate an Enumerable is // the enumerate function friend Enumerable enumerate(Container&&); @@ -46,16 +45,12 @@ namespace iter { friend Enumerable> enumerate( std::initializer_list); - // FIXME it seems like if an rvalue is passed, Container will - // not be a reference type at all, which will cause this to copy - // construct rather than move construct. But somehow that doesn't - // happen and it gets move constructed. Must investigate further + // Value constructor for use only in the enumerate function Enumerable(Container container) : container(std::forward(container)) { } public: - // Value constructor for use only in the enumerate function Enumerable() = delete; Enumerable& operator=(const Enumerable&) = delete; Enumerable(const Enumerable&) = delete; From b8fe3d8cdf3753eee1a0ee72005daa8b51d71229 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 11:20:11 -0700 Subject: [PATCH 0346/1866] adds test with temporaries --- tests/testchain.cpp | 66 +++++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/tests/testchain.cpp b/tests/testchain.cpp index 46ac02a3..99d7a291 100644 --- a/tests/testchain.cpp +++ b/tests/testchain.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -19,35 +20,42 @@ int main() { } } { - 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< 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'; + } } return 0; } From 32622e6fff816608ec018cd60a8eef46f6b993a6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 11:36:35 -0700 Subject: [PATCH 0347/1866] Complete rewrite of chain, safer, supports temps Supports temporary values the same way zip does. One thing I'd like to be able to do is support a mix of types so something like chain(std::vector{1,2,3,4}, range(10)); would work currently it doesnt because the iterators dereference to different types (int& and int, respectively). Idk if there's a safe way to handle this that wouldn't be confusing outwardly. --- chain.hpp | 219 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 127 insertions(+), 92 deletions(-) diff --git a/chain.hpp b/chain.hpp index d54b1426..0e57ce09 100644 --- a/chain.hpp +++ b/chain.hpp @@ -1,104 +1,139 @@ -#ifndef CHAIN_HPP -#define CHAIN_HPP - -#include "iterator_range.hpp" +#include "iterbase.hpp" #include #include +#include +#include namespace iter { - template - struct chain_iter; - template - struct chain_iter { - - private: - //using Iterator = decltype(std::declval().begin()); - using Iterator = decltype(std::begin(std::declval())); - Iterator begin; - const Iterator end;//never really used but kept it for consistency - - public: - chain_iter(Container && container, bool is_end=false) : - begin(std::begin(container)),end(std::end(container)) { - if(is_end) begin = std::end(container); - } - chain_iter & operator++() - { - ++begin; - return *this; - } - auto operator*()->decltype(*begin) - { - return *begin; - } - bool operator!=(const chain_iter & rhs) const{ - return this->begin != rhs.begin; - } - }; - template - struct chain_iter - { - private: - //using Iterator = decltype(std::declval().begin()); - using Iterator = decltype(std::begin(std::declval())); - Iterator begin; - const Iterator end; - bool end_reached = false; - chain_iter next_iter; - - public: - chain_iter(Container && container, Containers&& ... containers, bool is_end=false) : - begin(std::begin(container)), - end(std::end(container)), - next_iter(std::forward(containers)...,is_end) { - if(is_end) - begin = std::end(container); + template + class Chained; + + template + Chained chain(Containers&&...); + + template + class Chained { + friend Chained chain( + Container&&, RestContainers&&...); + template + friend class Chained; + + private: + Container container; + Chained rest_chained; + Chained(Container container, RestContainers&&... rest) + : container(std::forward(container)), + rest_chained{std::forward(rest)...} + { } + + public: + class Iterator { + 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)} + { } + + 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; } - chain_iter & operator++() - { - if (!(begin != end)) { - ++next_iter; + + bool operator!=(const Iterator& other) const { + return this->sub_iter != other.sub_iter || + this->rest_iter != other.rest_iter; } - else { - ++begin; + + iterator_deref operator*() { + return this->at_end ? + *this->rest_iter : *this->sub_iter; } - return *this; - } - auto operator*()->decltype(*begin) - { - if (!(begin != end)) { - return *next_iter; + }; + + Iterator begin() { + return {std::begin(this->container), + std::end(this->container), + std::begin(this->rest_chained)}; + } + + Iterator end() { + return {std::end(this->container), + std::end(this->container), + std::end(this->rest_chained)}; + } + }; + template + class Chained { + friend Chained chain(Container&&); + template + friend class Chained; + + private: + Container container; + Chained(Container container) + : container(std::forward(container)) + { } + + public: + class Iterator { + private: + iterator_type sub_iter; + const iterator_type sub_end; + + public: + Iterator(const iterator_type& s_begin, + const iterator_type& s_end) + : sub_iter{s_begin}, + sub_end{s_end} + { } + + Iterator& operator++() { + ++this->sub_iter; + return *this; } - else { - return *begin; + + bool operator!=(const Iterator& other) const { + return this->sub_iter != other.sub_iter; } - } - bool operator !=(const chain_iter & rhs) const { - if (!(begin != end)) { - return this->next_iter != rhs.next_iter; + + iterator_deref operator*() { + return *this->sub_iter; } - else - return this->begin != rhs.begin; - } - }; - - template - iterator_range> chain(Containers&& ... containers) - { - auto begin = - chain_iter(std::forward(containers)...); - auto end = - chain_iter(std::forward(containers)...,true); - return - iterator_range>(begin,end); - } -} -namespace std { - template - struct iterator_traits> { - using difference_type = ptrdiff_t; - using iterator_category = input_iterator_tag; - }; + }; + + Iterator begin() { + return {std::begin(this->container), + std::end(this->container)}; + } + + Iterator end() { + return {std::end(this->container), + std::end(this->container)}; + } + }; + + template + Chained chain(Containers&&... containers) { + return {std::forward(containers)...}; + } } -#endif //CHAIN_HPP From 38fe87b38a31874338f69ee1f34dd6d841050633 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 11:40:33 -0700 Subject: [PATCH 0348/1866] Adds back ziptest that uses chain --- tests/testzip.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/testzip.cpp b/tests/testzip.cpp index 3003bc40..06e3ebbf 100644 --- a/tests/testzip.cpp +++ b/tests/testzip.cpp @@ -95,9 +95,8 @@ int main() { std::cout< constvector{1.1,2.2,3.3,4.4}; for (auto e : zip( - // the chain test breaks it, but its chain's fault - //iter::chain(std::vector(5,5), - // std::array{{1,2}}), + 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}, @@ -106,7 +105,7 @@ int main() { std::cout << std::get<0>(e) << " " << std::get<1>(e) << " " - //<< std::get<2>(e) + << std::get<2>(e) << '\n'; } } From 9abb598e2041195b5087da64d04741329993419b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 12:10:16 -0700 Subject: [PATCH 0349/1866] removes 'const' from imap begin/end --- imap.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imap.hpp b/imap.hpp index 42fba58b..3cc01371 100644 --- a/imap.hpp +++ b/imap.hpp @@ -117,11 +117,11 @@ namespace iter { } }; - Iterator begin() const { + Iterator begin() { return {this->map_func, this->zipped.begin()}; } - Iterator end() const { + Iterator end() { return {this->map_func, this->zipped.end()}; } From 70323c5e3306df14d55f1e733a161cffc38a8ea0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 12:14:43 -0700 Subject: [PATCH 0350/1866] adds temporary test for imap --- tests/testimap.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/testimap.cpp b/tests/testimap.cpp index 328307b0..3d6f38ca 100644 --- a/tests/testimap.cpp +++ b/tests/testimap.cpp @@ -37,5 +37,9 @@ int main() { 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; } From 1f324105823c56ab2ef14f9c10cab75dfa5d0a7a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 15:30:09 -0700 Subject: [PATCH 0351/1866] removes const from begin/end --- accumulate.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index 792a27aa..fd671367 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -87,13 +87,13 @@ namespace iter { } }; - Iterator begin() const { + Iterator begin() { return {std::begin(this->container), std::end(this->container), this->accumulate_func}; } - Iterator end() const { + Iterator end() { return {std::end(this->container), std::end(this->container), this->accumulate_func}; From 97cb78e8bf7eea6e7642034d7f846d8ec3f20e3e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 15:31:10 -0700 Subject: [PATCH 0352/1866] removes const from begin/end --- compress.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compress.hpp b/compress.hpp index 34aa22cf..e6c5b852 100644 --- a/compress.hpp +++ b/compress.hpp @@ -115,12 +115,12 @@ namespace iter { } }; - Iterator begin() const { + Iterator begin() { return {std::begin(this->container), std::end(this->container), std::begin(this->selectors), std::end(this->selectors)}; } - Iterator end() const { + Iterator end() { return {std::end(this->container), std::end(this->container), std::end(this->selectors), std::end(this->selectors)}; } From b69d4f9cedead102ee3acabfdd54429ad23bf666 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 15:31:38 -0700 Subject: [PATCH 0353/1866] removes const from begin/end --- cycle.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cycle.hpp b/cycle.hpp index 7dc76424..76ee4fee 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -73,12 +73,12 @@ namespace iter { } }; - Iterator begin() const { + Iterator begin() { return {std::begin(this->container), std::end(this->container)}; } - Iterator end() const { + Iterator end() { return {std::end(this->container), std::end(this->container)}; } From bd3d5562e270d2cb0bb4ea99ee7d4264512c7228 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 15:32:23 -0700 Subject: [PATCH 0354/1866] removes const from begin/end --- dropwhile.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index 724f0122..8f85a55a 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -82,13 +82,13 @@ namespace iter { } }; - Iterator begin() const { + Iterator begin() { return {std::begin(this->container), std::end(this->container), this->filter_func}; } - Iterator end() const { + Iterator end() { return {std::end(this->container), std::end(this->container), this->filter_func}; From eb8e96443402c131f727823c823e12fc88444ed4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 15:33:32 -0700 Subject: [PATCH 0355/1866] removes bad include --- tests/testenumerate.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/testenumerate.cpp b/tests/testenumerate.cpp index cd41bc90..fcc1745c 100644 --- a/tests/testenumerate.cpp +++ b/tests/testenumerate.cpp @@ -1,5 +1,3 @@ -#include "testbase.hpp" - #include #include From 7ef021d4b1c9a597bfb34e5c6ac4dbc01c7d65bd Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 15:34:38 -0700 Subject: [PATCH 0356/1866] removes const from begin/end --- filter.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/filter.hpp b/filter.hpp index f6695d44..d8c67218 100644 --- a/filter.hpp +++ b/filter.hpp @@ -86,13 +86,13 @@ namespace iter { } }; - Iterator begin() const { + Iterator begin() { return {std::begin(this->container), std::end(this->container), this->filter_func}; } - Iterator end() const { + Iterator end() { return {std::end(this->container), std::end(this->container), this->filter_func}; From 78c0c9023d7b506fff8c098658e28b7b83ccf9d9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 15:35:29 -0700 Subject: [PATCH 0357/1866] removes const from begin/end --- groupby.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index 39cce2f8..ec956012 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -193,24 +193,24 @@ namespace iter { } }; - GroupIterator begin() const { + GroupIterator begin() { return {*this, key}; } - GroupIterator end() const { + GroupIterator end() { return {*this, key}; } }; - Iterator begin() const { + Iterator begin() { return {std::begin(this->container), std::end(this->container), this->key_func}; } - Iterator end() const { + Iterator end() { return {std::end(this->container), std::end(this->container), this->key_func}; From c74d20a397908fcb7188801e183397f486e69145 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 15:36:06 -0700 Subject: [PATCH 0358/1866] removes const from begin/end --- slice.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/slice.hpp b/slice.hpp index f7a074a4..ec3035f1 100644 --- a/slice.hpp +++ b/slice.hpp @@ -129,12 +129,12 @@ namespace iter { } }; - Iterator begin() const { + Iterator begin() { return {std::next(std::begin(this->container), this->start), this->start, this->stop, this->step}; } - Iterator end() const { + Iterator end() { return {std::next(std::begin(this->container), this->stop), this->stop, this->stop, this->step}; } From 33614c90f4e52a0199204c61eef6b4b3ddbadac5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 15:36:48 -0700 Subject: [PATCH 0359/1866] removes const from begin/end --- takewhile.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/takewhile.hpp b/takewhile.hpp index d534b2f2..5fadc0ce 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -93,13 +93,13 @@ namespace iter { } }; - Iterator begin() const { + Iterator begin() { return {std::begin(this->container), std::end(this->container), this->filter_func}; } - Iterator end() const { + Iterator end() { return {std::end(this->container), std::end(this->container), this->filter_func}; From 59caddfe96a3656155d439e6c91a34b7cfd936f9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 15:55:43 -0700 Subject: [PATCH 0360/1866] Adds accumulate test with temporary --- tests/testaccumulate.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/testaccumulate.cpp b/tests/testaccumulate.cpp index a65bf7b9..2321ffca 100644 --- a/tests/testaccumulate.cpp +++ b/tests/testaccumulate.cpp @@ -25,5 +25,9 @@ int main() { 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; } From 19094116c04abfc678feffa5c43db9a8752b0828 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 16:01:19 -0700 Subject: [PATCH 0361/1866] Corrects support for temporaries in accumulate --- accumulate.hpp | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index fd671367..8ba6bcba 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace iter { @@ -20,29 +21,28 @@ namespace iter { template Accumulator, AccumulateFunc> accumulate( - std::initializer_list&&, AccumulateFunc); + std::initializer_list, AccumulateFunc); template class Accumulator { private: - Container& container; + Container container; AccumulateFunc accumulate_func; - // The accumulate function is the only thing allowed to create a Accumulator friend Accumulator accumulate( Container&&, AccumulateFunc); template friend Accumulator, AF> accumulate( - std::initializer_list&&, AF); + std::initializer_list, AF); // Value constructor for use only in the accumulate function Accumulator(Container&& container, AccumulateFunc accumulate_func) - : container{container}, + : container(std::forward(container)), accumulate_func(accumulate_func) { } - Accumulator () = delete; - Accumulator & operator=(const Accumulator&) = delete; + Accumulator() = delete; + Accumulator& operator=(const Accumulator&) = delete; public: Accumulator(const Accumulator&) = default; @@ -50,9 +50,14 @@ namespace iter { class Iterator { // AccumVal must be default constructible using AccumVal = - typename std::result_of, - iterator_deref)>::type; + typename std::remove_reference< + typename std::result_of, + iterator_deref)>::type>::type; + static_assert( + std::is_default_constructible::value, + "Cannot accumulate a non-default constructible type"); + private: iterator_type sub_iter; const iterator_type sub_end; @@ -113,22 +118,24 @@ namespace iter { template auto accumulate(Container&& container) -> decltype(accumulate(std::forward(container), - std::plus>{})) + std::plus>::type>{})) { return accumulate(std::forward(container), - std::plus>{}); + std::plus>::type>{}); } template Accumulator, AccumulateFunc> accumulate( - std::initializer_list&& il, + std::initializer_list il, AccumulateFunc accumulate_func) { return {std::move(il), accumulate_func}; } template - auto accumulate(std::initializer_list&& il) -> + auto accumulate(std::initializer_list il) -> decltype(accumulate(std::move(il), std::plus{})) { return accumulate(std::move(il), std::plus{}); From 60c34f2e2e1034e876f0ce6c2ad298f4fb985e04 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 16:14:22 -0700 Subject: [PATCH 0362/1866] Adds compress test with temporaries --- tests/testcompress.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/testcompress.cpp b/tests/testcompress.cpp index ebbeb642..5197f3e2 100644 --- a/tests/testcompress.cpp +++ b/tests/testcompress.cpp @@ -53,6 +53,14 @@ int main(void) { 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; From 58723f241db377739cc1886b4e72fba3e695e147 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 16:16:11 -0700 Subject: [PATCH 0363/1866] Corrects support for temporaries in compress --- compress.hpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/compress.hpp b/compress.hpp index e6c5b852..94dff629 100644 --- a/compress.hpp +++ b/compress.hpp @@ -17,21 +17,21 @@ namespace iter { template Compressed, Selector> compress( - std::initializer_list&&, Selector&&); + std::initializer_list, Selector&&); template Compressed> compress( - Container&&, std::initializer_list&&); + Container&&, std::initializer_list); template Compressed, std::initializer_list> compress( - std::initializer_list&&, std::initializer_list&&); + std::initializer_list, std::initializer_list); template class Compressed { private: - Container& container; - Selector & selectors; + Container container; + Selector selectors; // The only thing allowed to directly instantiate an Compressed is // the compress function @@ -40,24 +40,24 @@ namespace iter { template friend Compressed, Sel> compress( - std::initializer_list&&, Sel&&); + std::initializer_list, Sel&&); template friend Compressed> compress( - Con&&, std::initializer_list&&); + Con&&, std::initializer_list); template friend Compressed, std::initializer_list> compress( - std::initializer_list&&, std::initializer_list&&); + std::initializer_list, std::initializer_list); // Selector::Iterator type using selector_iter_type = decltype(std::begin(selectors)); // Value constructor for use only in the compress function - Compressed(Container&& container, Selector&& selectors) - : container{container}, - selectors{selectors} + Compressed(Container container, Selector selectors) + : container(std::forward(container)), + selectors(std::forward(selectors)) { } Compressed() = delete; Compressed& operator=(const Compressed&) = delete; @@ -137,22 +137,22 @@ namespace iter { template Compressed, Selector> compress( - std::initializer_list&& data, Selector&& selectors) { + std::initializer_list data, Selector&& selectors) { return {std::move(data), std::forward(selectors)}; } template Compressed> compress( - Container&& container, std::initializer_list&& selectors) { + Container&& container, std::initializer_list selectors) { return {std::forward(container), std::move(selectors)}; } template Compressed, std::initializer_list> compress( - std::initializer_list&& data, - std::initializer_list&& selectors) { + std::initializer_list data, + std::initializer_list selectors) { return {std::move(data), std::move(selectors)}; } From 2bdb9bf2824aa0fa9ea282add83e103b7cb90b3d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 16:24:15 -0700 Subject: [PATCH 0364/1866] Adds cycle test with temporaries --- tests/testcycle.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/testcycle.cpp b/tests/testcycle.cpp index d7c0f91b..138692cc 100644 --- a/tests/testcycle.cpp +++ b/tests/testcycle.cpp @@ -57,5 +57,14 @@ int main() { ++count; } + count = 0; + for (auto i : std::vector{1,2,3,4,5}) { + std::cout << i << '\n'; + if (count == 20) { + break; + } + ++count; + } + return 0; } From 0e979404ebcec5a98bcab293e30152b9552c57ad Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 16:24:27 -0700 Subject: [PATCH 0365/1866] Corrects support for temporaries in cycle --- cycle.hpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/cycle.hpp b/cycle.hpp index 76ee4fee..7c2cd8b2 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -17,7 +17,7 @@ namespace iter { Cycle cycle(Container&&); template - Cycle> cycle(std::initializer_list&&); + Cycle> cycle(std::initializer_list); template class Cycle { @@ -26,12 +26,14 @@ namespace iter { friend Cycle cycle(Container&&); template friend Cycle> cycle( - std::initializer_list&&); + std::initializer_list); - Container& container; + Container container; // Value constructor for use only in the cycle function - Cycle(Container&& container) : container{container} { } + Cycle(Container container) + : container(std::forward(container)) + { } Cycle() = delete; Cycle& operator=(const Cycle&) = delete; @@ -92,7 +94,7 @@ namespace iter { } template - Cycle> cycle(std::initializer_list&& il) + Cycle> cycle(std::initializer_list il) { return {std::move(il)}; } From f8f9773953110cd58bd4877601719ba5f5ef7e04 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 16:25:31 -0700 Subject: [PATCH 0366/1866] removes extra && from ctor args --- accumulate.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accumulate.hpp b/accumulate.hpp index 8ba6bcba..ef4ed42c 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -37,7 +37,7 @@ namespace iter { std::initializer_list, AF); // Value constructor for use only in the accumulate function - Accumulator(Container&& container, AccumulateFunc accumulate_func) + Accumulator(Container container, AccumulateFunc accumulate_func) : container(std::forward(container)), accumulate_func(accumulate_func) { } From 7732769d68d685bd8f8d9759051027e6a956db27 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 16:33:54 -0700 Subject: [PATCH 0367/1866] Adds dropwhile temporary test and asserts --- tests/testdropwhile.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/testdropwhile.cpp b/tests/testdropwhile.cpp index 8413e291..3140f81a 100644 --- a/tests/testdropwhile.cpp +++ b/tests/testdropwhile.cpp @@ -3,15 +3,19 @@ #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)) { + 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'; @@ -22,5 +26,10 @@ int main() { 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; } From f3d24fff954ca8b40d55566468c108e034679db7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 16:36:20 -0700 Subject: [PATCH 0368/1866] Corrects temporary support in dropwhile --- dropwhile.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index 8f85a55a..fe727916 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -18,12 +18,12 @@ namespace iter { template DropWhile> dropwhile( - FilterFunc, std::initializer_list&&); + FilterFunc, std::initializer_list); template class DropWhile { private: - Container& container; + Container container; FilterFunc filter_func; friend DropWhile dropwhile( @@ -31,11 +31,11 @@ namespace iter { template friend DropWhile> dropwhile( - FF, std::initializer_list&&); + FF, std::initializer_list); // Value constructor for use only in the dropwhile function - DropWhile(FilterFunc filter_func, Container&& container) - : container{container}, + DropWhile(FilterFunc filter_func, Container container) + : container(std::forward(container)), filter_func(filter_func) { } DropWhile() = delete; @@ -105,7 +105,7 @@ namespace iter { template DropWhile> dropwhile( - FilterFunc filter_func, std::initializer_list&& il) + FilterFunc filter_func, std::initializer_list il) { return {filter_func, std::move(il)}; } From af151faf223c95be4bb4f6e4b6c8c32e24004566 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 16:47:26 -0700 Subject: [PATCH 0369/1866] Adds filter test with temporary --- tests/testfilter.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/testfilter.cpp b/tests/testfilter.cpp index 0b0b4865..e8af2aab 100644 --- a/tests/testfilter.cpp +++ b/tests/testfilter.cpp @@ -72,5 +72,12 @@ int main() { 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; } From f66ca160b8f0f8b811655c84b74a41cdf011051f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 16:47:42 -0700 Subject: [PATCH 0370/1866] Corrects support for temporaries in filter --- filter.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/filter.hpp b/filter.hpp index d8c67218..870cc2e2 100644 --- a/filter.hpp +++ b/filter.hpp @@ -18,12 +18,12 @@ namespace iter { template Filter> filter( - FilterFunc, std::initializer_list&&); + FilterFunc, std::initializer_list); template class Filter { private: - Container& container; + Container container; FilterFunc filter_func; // The filter function is the only thing allowed to create a Filter @@ -32,11 +32,11 @@ namespace iter { template friend Filter> filter( - FF, std::initializer_list&&); + FF, std::initializer_list); // Value constructor for use only in the filter function - Filter(FilterFunc filter_func, Container&& container) - : container{container}, + Filter(FilterFunc filter_func, Container container) + : container(std::forward(container)), filter_func(filter_func) { } Filter() = delete; @@ -110,7 +110,7 @@ namespace iter { template Filter> filter( FilterFunc filter_func, - std::initializer_list&& il) + std::initializer_list il) { return {filter_func, std::move(il)}; } From 6fbd9f2274bbef27dfd0f0aff93787d83b899672 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 16:50:06 -0700 Subject: [PATCH 0371/1866] Corrects init list support in filter false --- filterfalse.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/filterfalse.hpp b/filterfalse.hpp index 3beaaef3..27e8cf03 100644 --- a/filterfalse.hpp +++ b/filterfalse.hpp @@ -74,7 +74,7 @@ namespace iter { //specializations for initializer_lists template - auto filterfalse(FilterFunc filter_func, std::initializer_list&& container) -> + auto filterfalse(FilterFunc filter_func, std::initializer_list container) -> decltype(filter( detail::PredicateFlipper>( filter_func), @@ -87,7 +87,7 @@ namespace iter { // Single argument version, uses a BoolFlipper to reverse the truthiness // of an object template - auto filterfalse(std::initializer_list&& container) -> + auto filterfalse(std::initializer_list container) -> decltype(filter( detail::BoolFlipper>(), std::move(container))) { From 429d18f72195b200c458dbeb8d67e1fe03d13ca6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 16:51:14 -0700 Subject: [PATCH 0372/1866] removes extra && --- filter.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/filter.hpp b/filter.hpp index 870cc2e2..d8986128 100644 --- a/filter.hpp +++ b/filter.hpp @@ -143,7 +143,7 @@ namespace iter { } template - auto filter(std::initializer_list&& il) -> + auto filter(std::initializer_list il) -> decltype(filter( detail::BoolTester>(), std::move(il))) { From 6abd33956c74458670ced35fd79dcf2fa4c1c39a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 16:53:14 -0700 Subject: [PATCH 0373/1866] Adds filterfalse test with temporaries --- tests/testfilterfalse.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/testfilterfalse.cpp b/tests/testfilterfalse.cpp index 0ff0fad0..9063d0bf 100644 --- a/tests/testfilterfalse.cpp +++ b/tests/testfilterfalse.cpp @@ -83,5 +83,11 @@ int main() { 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; } From 4a7fb3250f5feb8d23693f71a0d71753d5c567d8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 16:58:45 -0700 Subject: [PATCH 0374/1866] Add groupby test with temporary --- tests/testgroupby.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/testgroupby.cpp b/tests/testgroupby.cpp index 89aace14..9fc03ee3 100644 --- a/tests/testgroupby.cpp +++ b/tests/testgroupby.cpp @@ -89,6 +89,18 @@ int main() } 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; From fb8d17fdbbf4da77e2ca39ea399e1381c8ecc67f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 17:01:36 -0700 Subject: [PATCH 0375/1866] Corrects support for temporaries in groupby --- groupby.hpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index ec956012..51360bfb 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -17,30 +17,26 @@ namespace iter { template GroupBy, KeyFunc> groupby( - std::initializer_list&&, KeyFunc); + std::initializer_list, KeyFunc); template class GroupBy { private: - Container& container; + Container container; KeyFunc key_func; friend GroupBy groupby(Container&&, KeyFunc); template friend GroupBy, KF> groupby( - std::initializer_list&&, KF); - - - - + std::initializer_list, KF); using key_func_ret = decltype(std::declval()( std::declval>())); - GroupBy(Container&& container, KeyFunc key_func) - : container{container}, + GroupBy(Container container, KeyFunc key_func) + : container(std::forward(container)), key_func(key_func) { } @@ -249,13 +245,13 @@ namespace iter { template GroupBy, KeyFunc> groupby( - std::initializer_list&& il, KeyFunc key_func) { + std::initializer_list il, KeyFunc key_func) { return {std::move(il), key_func}; } template - auto groupby(std::initializer_list&& il) -> + auto groupby(std::initializer_list il) -> decltype(groupby(std::move(il), ItemReturner>())) { return groupby( From 4d7453ecddaf170500d8a00d09bf380c287c0548 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 17:18:42 -0700 Subject: [PATCH 0376/1866] Adds sorted test with temporary --- tests/testsorted.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/testsorted.cpp b/tests/testsorted.cpp index 2a0bea29..aed57d32 100644 --- a/tests/testsorted.cpp +++ b/tests/testsorted.cpp @@ -8,7 +8,7 @@ using iter::sorted; int main() { - std::vector vec = {19, 3, 45, 32, 10, 0, 90, 15, 1, 7, 5, 6, 69}; + std::vector vec = {19, 45, 32, 10, 0, 90, 15, 1, 7, 5, 6, 69}; for (auto i : sorted(vec)) { std::cout << i << '\n'; } @@ -28,5 +28,9 @@ int main() } + for (auto i : sorted( + std::vector{19, 45, 32, 10, 0, 90, 15, 1, 7, 5, 6, 69})) { + std::cout << i << '\n'; + } return 0; } From 46e75b4df0085b6e1e31a590a1413ad92c51cd62 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 17:38:09 -0700 Subject: [PATCH 0377/1866] Adds support for temporaries to sorted +more This one was weird because sorted didn't support temporaries at all previously. Additionally it was using the older style of getting the iterator type and dereferencing type, rather that doing iterator_type and deref. It's much better now. --- sorted.hpp | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/sorted.hpp b/sorted.hpp index 15d36b22..349fc881 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -12,28 +12,32 @@ namespace iter { class Sorted; template - Sorted sorted(Container&, CompareFunc); + Sorted sorted(Container&&, CompareFunc); template class Sorted { private: + Container container; + std::vector> sorted_iters; + friend Sorted - sorted(Container&, CompareFunc); + sorted(Container&&, CompareFunc); - std::vector> sorted_iters; + using sorted_iter_type = iterator_type; - using sorted_iter_type = decltype(std::begin(sorted_iters)); Sorted() = delete; Sorted& operator=(const Sorted&) = delete; - Sorted(Container& container, CompareFunc compare_func) { + Sorted(Container in_container, CompareFunc compare_func) + : container(std::forward(in_container)) + { // Fill the sorted_iters vector with an iterator to each // element in the container - for (auto iter = std::begin(container); - iter != std::end(container); + for (auto iter = std::begin(this->container); + iter != std::end(this->container); ++iter) { - sorted_iters.push_back(iter); + this->sorted_iters.push_back(iter); } // sort by comparing the elements that the iterators point to @@ -74,24 +78,18 @@ namespace iter { template Sorted sorted( - Container& container, CompareFunc compare_func) { - return {container, compare_func}; + Container&& container, CompareFunc compare_func) { + return {std::forward(container), compare_func}; } template - auto sorted(Container& container) -> - decltype(sorted( - container, - std::less()))>() - )) + auto sorted(Container&& container) -> + decltype(sorted(std::forward(container), + std::less>())) { - return sorted( - container, - std::less()))>() - ); - } + return sorted(std::forward(container), + std::less>()); + } } From 395e704111f094eaa37219debc0e49c823a8a059 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 17:47:38 -0700 Subject: [PATCH 0378/1866] Corrects support for temporaries in takewhile --- takewhile.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/takewhile.hpp b/takewhile.hpp index 5fadc0ce..528f6fb0 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -18,12 +18,12 @@ namespace iter { template TakeWhile> takewhile( - FilterFunc, std::initializer_list&&); + FilterFunc, std::initializer_list); template class TakeWhile { private: - Container& container; + Container container; FilterFunc filter_func; friend TakeWhile takewhile( @@ -31,11 +31,11 @@ namespace iter { template friend TakeWhile> takewhile( - FF, std::initializer_list&&); + FF, std::initializer_list); // Value constructor for use only in the takewhile function - TakeWhile(FilterFunc filter_func, Container&& container) - : container{container}, + TakeWhile(FilterFunc filter_func, Container container) + : container(std::forward(container)), filter_func(filter_func) { } @@ -116,7 +116,7 @@ namespace iter { template TakeWhile> takewhile( - FilterFunc filter_func, std::initializer_list&& il) + FilterFunc filter_func, std::initializer_list il) { return {filter_func, std::move(il)}; } From b02bee7407d83b8ddb3191ed7df49dba6585f027 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 20:10:33 -0700 Subject: [PATCH 0379/1866] Adds slice test with temporary --- tests/testslice.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/testslice.cpp b/tests/testslice.cpp index cc19f455..eaf8e1ce 100644 --- a/tests/testslice.cpp +++ b/tests/testslice.cpp @@ -1,7 +1,8 @@ +#include + #include #include -#include #include #include @@ -71,4 +72,10 @@ int main() { std::cout << i << '\n'; } + std::cout << "\nvector temporary\n"; + for (auto i : iter::slice( + std::vector{1, 2, 4, 8, 16, 32, 64, 128}, 2, 6)) { + std::cout << i << '\n'; + } + } From 84f0cbc2018b6aa6708f882d96456fe37aeaaaaf Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 20:11:18 -0700 Subject: [PATCH 0380/1866] Corrects slice temporary support --- slice.hpp | 52 +++++++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/slice.hpp b/slice.hpp index ec3035f1..7e1e0d26 100644 --- a/slice.hpp +++ b/slice.hpp @@ -15,7 +15,7 @@ namespace iter { //class Slice; //template - //Slice> slice( std::initializer_list &&); + //Slice> slice( std::initializer_list); //template //Slice slice(Container &&); @@ -33,19 +33,19 @@ namespace iter { enum { value = sizeof(test(0)) == sizeof(char) }; }; template - typename std::enable_if::value,size_t>::type - size(Container & container) { + typename std::enable_if::value, std::size_t>::type + size(const Container& container) { return container.size(); } template - typename std::enable_if::value,size_t>::type - size(Container & container) { + typename std::enable_if::value, std::size_t>::type + size(const Container& container) { return std::distance(std::begin(container), std::end(container)); } - template - size_t size(T (&)[N]) { + template + std::size_t size(const T (&)[N]) { return N; } @@ -54,7 +54,7 @@ namespace iter { template class Slice { private: - Container & container; + Container container; DifferenceType start; DifferenceType stop; DifferenceType step; @@ -63,17 +63,11 @@ namespace iter { // the slice function //friend Slice slice(Container &&); //template - //friend Slice> slice(std::initializer_list &&); - - - - - - + //friend Slice> slice(std::initializer_list); public: - Slice(Container & container, DifferenceType start, + Slice(Container in_container, DifferenceType start, DifferenceType stop, DifferenceType step) - : container{container}, + : container(std::forward(in_container)), start{start}, stop{stop}, step{step} @@ -83,16 +77,20 @@ namespace iter { (start > stop && step >=0)){ this->stop = start; } - if (this->stop > static_cast(size(container))) { - this->stop = static_cast(size(container)); + if (this->stop > static_cast( + size(this->container))) { + this->stop = static_cast(size( + this->container)); + std::cout << "stop is too large\n"; + std::cout << "stop is now: " << this->stop << '\n'; } if (this->start < 0) { this->start = 0; } } - Slice () = delete; - Slice & operator=(const Slice &) = delete; + Slice() = delete; + Slice& operator=(const Slice&) = delete; Slice(const Slice &) = default; @@ -117,7 +115,7 @@ namespace iter { return *this->sub_iter; } - Iterator & operator++() { + Iterator& operator++() { std::advance(this->sub_iter, this->step); this->current += this->step; return *this; @@ -144,28 +142,28 @@ namespace iter { // Helper function to instantiate a Slice template Slice slice( - Container && container, DifferenceType start, - DifferenceType stop, DifferenceType step=1) { + Container&& container, + DifferenceType start, DifferenceType stop, DifferenceType step=1) { return {std::forward(container), start, stop, step}; } //only give the end as an arg and assume step is 1 and begin is 0 template Slice slice( - Container && container, DifferenceType stop) { + Container&& container, DifferenceType stop) { return {std::forward(container), 0, stop, 1}; } template Slice, DifferenceType> slice( - std::initializer_list && il, DifferenceType start, + std::initializer_list il, DifferenceType start, DifferenceType stop, DifferenceType step=1) { return {il, start, stop, step}; } template Slice, DifferenceType> slice( - std::initializer_list && il, DifferenceType stop) { + std::initializer_list il, DifferenceType stop) { return {il, 0, stop, 1}; } } From 70b0668cbf1d33a102637ce7c6381ef1ab08367e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Jun 2014 20:20:20 -0700 Subject: [PATCH 0381/1866] Adds takewhile test with temporary --- tests/testtakewhile.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/testtakewhile.cpp b/tests/testtakewhile.cpp index 6cbd6e17..bec3aeae 100644 --- a/tests/testtakewhile.cpp +++ b/tests/testtakewhile.cpp @@ -22,5 +22,11 @@ int main() { 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; } From 6c962c9d0e4bac9d1558c1287607f23b60886b15 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 2 Jun 2014 22:19:12 -0700 Subject: [PATCH 0382/1866] renames reverse -> reversed --- reverse.hpp => reversed.hpp | 0 tests/{testreverse.cpp => testreversed.cpp} | 12 ++++++------ 2 files changed, 6 insertions(+), 6 deletions(-) rename reverse.hpp => reversed.hpp (100%) rename tests/{testreverse.cpp => testreversed.cpp} (66%) diff --git a/reverse.hpp b/reversed.hpp similarity index 100% rename from reverse.hpp rename to reversed.hpp diff --git a/tests/testreverse.cpp b/tests/testreversed.cpp similarity index 66% rename from tests/testreverse.cpp rename to tests/testreversed.cpp index 089de31b..d2ca082a 100644 --- a/tests/testreverse.cpp +++ b/tests/testreversed.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -9,23 +9,23 @@ int main () { { std::vector a{1,2,3,4,5,6,7}; std::vector b{"hey","how","are","you","doing"}; - std::cout << std::endl << "Reverse range test" << std::endl << std::endl; - for (auto i : iter::reverse(a)) { + std::cout << std::endl << "reversed range test" << std::endl << std::endl; + for (auto i : iter::reversed(a)) { std::cout << i << std::endl; } std::cout< Date: Mon, 2 Jun 2014 22:19:28 -0700 Subject: [PATCH 0383/1866] renames reverse -> reversed --- reversed.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reversed.hpp b/reversed.hpp index 14e8352c..0833f9a0 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -5,7 +5,7 @@ namespace iter { template - auto reverse(Container && container) -> iterator_range + auto reversed(Container && container) -> iterator_range { return iterator_range(container.rbegin(),container.rend()); From 98fa5b8186d3ab1cba278fd6347ac0c78c30e8c7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 2 Jun 2014 22:20:52 -0700 Subject: [PATCH 0384/1866] renames reverse in SConstruct --- tests/SConstruct | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/SConstruct b/tests/SConstruct index e38c0914..7c0b7cb9 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -5,6 +5,7 @@ env = Environment( CXX='c++', CXXFLAGS= ['-g', '-Wall', '-Wextra', '-pedantic', '-std=c++11', + '-fdiagnostics-color=always', '-I/usr/local/include'], CPPPATH='..', LINKFLAGS='-L/usr/local/lib') @@ -19,7 +20,7 @@ progs = Split(''' range zip slice - reverse + reversed filter repeat takewhile @@ -37,7 +38,6 @@ progs = Split(''' filterfalse grouper chain - command_chains groupby sorted unique_justseen From 0e82aa0272be2c22be6f9ba3c6e33775c1890453 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 2 Jun 2014 22:38:01 -0700 Subject: [PATCH 0385/1866] Adds reversed test with temporary --- tests/testreversed.cpp | 49 +++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/tests/testreversed.cpp b/tests/testreversed.cpp index d2ca082a..433e0c80 100644 --- a/tests/testreversed.cpp +++ b/tests/testreversed.cpp @@ -6,27 +6,32 @@ #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< 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 << std::endl; + } + + } From e99a5af0748ebf780775d4658f63c6898b146d90 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 2 Jun 2014 22:38:16 -0700 Subject: [PATCH 0386/1866] Reverse support for temporaries --- reversed.hpp | 77 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 68 insertions(+), 9 deletions(-) diff --git a/reversed.hpp b/reversed.hpp index 0833f9a0..4f721f3e 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -1,15 +1,74 @@ -#ifndef REVERSE_HPP -#define REVERSE_HPP +#ifndef REVERSE_HPP__ +#define REVERSE_HPP__ -#include "iterator_range.hpp" +#include "iterbase.hpp" + +#include +#include namespace iter { + + //Forward declarations of Reverser and reversed + template + class Reverser; + + template + Reverser reversed(Container&&); + + template + class Reverser { + private: + Container container; + // The reversed function is the only thing allowed to create a + // Reverser + friend Reverser reversed(Container&&); + + // Value constructor for use only in the reversed function + Reverser(Container container) + : container(std::forward(container)) + { } + Reverser() = delete; + Reverser& operator=(const Reverser&) = delete; + + public: + Reverser(const Reverser&) = default; + class Iterator { + private: + reverse_iterator_type sub_iter; + public: + Iterator (reverse_iterator_type iter) + : sub_iter{iter} + { } + + reverse_iterator_deref operator*() { + return *this->sub_iter; + } + + Iterator& operator++() { + ++this->sub_iter; + return *this; + } + + bool operator!=(const Iterator& other) const { + return this->sub_iter != other.sub_iter; + } + }; + + Iterator begin() { + return {this->container.rbegin()}; + } + + Iterator end() { + return {this->container.rend()}; + } + + }; + + // Helper function to instantiate an Filter template - auto reversed(Container && container) -> iterator_range - { - return - iterator_range(container.rbegin(),container.rend()); - } + Reverser reversed(Container&& container) { + return {std::forward(container)}; + } } -#endif //REVERSE_HPP +#endif //REVERSE_HPP__ From c3c666071e59f6717c320fb37c7da0f65c993d7e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 2 Jun 2014 22:54:02 -0700 Subject: [PATCH 0387/1866] small comment fix --- cycle.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cycle.hpp b/cycle.hpp index 7c2cd8b2..d683b8da 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -87,7 +87,7 @@ namespace iter { }; - // Helper function to instantiate an Filter + // Helper function to instantiate a Cycle template Cycle cycle(Container&& container) { return {std::forward(container)}; From 19da133195af594bd384aea86fe748f75b12dddc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 2 Jun 2014 23:25:54 -0700 Subject: [PATCH 0388/1866] Support for statically allocated arrays in reversed --- reversed.hpp | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 88 insertions(+), 2 deletions(-) diff --git a/reversed.hpp b/reversed.hpp index 4f721f3e..0cd836e1 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -7,7 +7,6 @@ #include namespace iter { - //Forward declarations of Reverser and reversed template class Reverser; @@ -15,6 +14,7 @@ namespace iter { template Reverser reversed(Container&&); + template class Reverser { private: @@ -64,11 +64,97 @@ namespace iter { }; - // Helper function to instantiate an Filter + // Helper function to instantiate a Reverser template Reverser reversed(Container&& container) { return {std::forward(container)}; } + + // + // + // specialization for statically allocated arrays + // this involves some tricks + // + template + Reverser reversed(T (&)[N]); + + template + class Reverser { + private: + T *array; + // The reversed function is the only thing allowed to create a + // Reverser + friend Reverser reversed(T (&)[N]); + + // Value constructor for use only in the reversed function + Reverser(T *array) + : array{array} + { } + Reverser() = delete; + Reverser& operator=(const Reverser&) = delete; + + public: + Reverser(const Reverser&) = default; + class Iterator { + private: + T *sub_iter; + T *stop; + T *dummy_end; + public: + // iter should be the last element in the array + // stop should be the first element + // dummy should be what iter is set to when complete + // the implementation below sets the dummy to one-past- + // the end, since that's the only non-nullptr value that + // the pointer can be set to that is also not a part + // of the actual array + Iterator (T *iter, T *stop, T *dummy) + : sub_iter{iter}, + stop{stop}, + dummy_end{dummy} + { } + + auto operator*() -> decltype(*array) { + return *this->sub_iter; + } + + Iterator& operator++() { + if (this->sub_iter == this->stop) { + this->sub_iter = this->dummy_end; + } else { + // decrementing the pointer is going forwards + // in the reversed direction + --this->sub_iter; + } + return *this; + } + + bool operator!=(const Iterator& other) const { + return this->sub_iter != other.sub_iter; + } + }; + + T *dummy_end() const { + return this->array + N; + } + + Iterator begin() { + return {this->array + N - 1, + this->array, + this->dummy_end()}; + } + + Iterator end() { + return {this->dummy_end(), this->dummy_end(), this->dummy_end()}; + } + + }; + + template + Reverser reversed(T (&array)[N]) { + return {array}; + } + } #endif //REVERSE_HPP__ From 41b1e8270ff9441028505991b89da7eda414971e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 2 Jun 2014 23:26:18 -0700 Subject: [PATCH 0389/1866] Adds deduction for reverse_iterator type --- iterbase.hpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/iterbase.hpp b/iterbase.hpp index 84fa8c32..85595b3a 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -22,6 +22,17 @@ namespace iter { template using iterator_deref = decltype(*std::declval&>()); + + // iterator_type is the type of C's iterator + template + using reverse_iterator_type = + decltype(std::declval().rbegin()); + + // iterator_deref is the type obtained by dereferencing an iterator + // to an object of type C + template + using reverse_iterator_deref = + decltype(*std::declval&>()); } #endif // #ifndef ITERBASE__HPP__ From a6be8b21fb206f8d2fbd3d46fa444540baafe3f9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 2 Jun 2014 23:27:16 -0700 Subject: [PATCH 0390/1866] changeds reverse to reversed in gitignore --- tests/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/.gitignore b/tests/.gitignore index de362625..87ae4e97 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -7,7 +7,7 @@ testenumerate testrange testslice testzip -testreverse +testreversed testrepeat testfilter testzip_longest From f3636aefe7c71126c3b774ad697f3fbbd5e0f0c9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 2 Jun 2014 23:27:54 -0700 Subject: [PATCH 0391/1866] adds reversed test with statically allocated array --- tests/testreversed.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/testreversed.cpp b/tests/testreversed.cpp index 433e0c80..c6d0ab46 100644 --- a/tests/testreversed.cpp +++ b/tests/testreversed.cpp @@ -30,7 +30,13 @@ int main () { std::cout << "with temporary\n"; for (auto i : iter::reversed(std::vector{1, 2, 3, 4, 5, 6, 7})) { - std::cout << i << std::endl; + 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'; } From c42864d1b59e679dbafaa76c6607d4bea202fc11 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 3 Jun 2014 22:16:17 -0700 Subject: [PATCH 0392/1866] replaces reverse with reversed in readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d8a4bd0b..a5964bef 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ evaluation wherever possible. [accumulate](#accumulate)
[compress](#compress)
[chain](#chain)
-[reverse](#reverse)
+[reversed](#reversed)
[slice](#slice)
[sliding_window](#sliding_window)
[grouper](#grouper)
@@ -352,13 +352,13 @@ for (auto i : chain(empty,vec1,arr1)) { } ``` -reverse +reversed ------- Iterates over elements of a sequence in reverse order. ```c++ -for (auto i : reverse(a)) { +for (auto i : reversed(a)) { cout << i << '\n'; } ``` From 9d90f0883a5e3ec97b1d47cf114e18fb1f03fb4b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 3 Jun 2014 22:17:41 -0700 Subject: [PATCH 0393/1866] Renames reverse to reversed in itertools.hpp --- itertools.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/itertools.hpp b/itertools.hpp index 5b038ef8..67a59e37 100644 --- a/itertools.hpp +++ b/itertools.hpp @@ -21,7 +21,7 @@ #include "product.hpp" #include "range.hpp" #include "repeat.hpp" -#include "reverse.hpp" +#include "reversed.hpp" #include "slice.hpp" #include "sorted.hpp" #include "takewhile.hpp" From 773d434b116a07daa18b7b1c0ec0a7ad11a2f220 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 7 Jun 2014 23:29:05 -0700 Subject: [PATCH 0394/1866] adds tests for movable temporaries --- tests/testrepeat.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/testrepeat.cpp b/tests/testrepeat.cpp index eb414685..b91fba03 100644 --- a/tests/testrepeat.cpp +++ b/tests/testrepeat.cpp @@ -3,6 +3,7 @@ #include #include #include +#include int main () { int a = 10; @@ -16,4 +17,15 @@ int main () { for (auto num : iter::repeat(a,10)) {//goes ten times std::cout << num << std::endl; } + + std::cout << "with temporary\n"; + for (auto s : iter::repeat(std::string{"hey"}, 2)) { + std::cout << s << '\n'; + } + + std::cout << "with uptr temporary\n"; + for (auto& p : iter::repeat(std::unique_ptr{new int{2}}, 2)) { + std::cout << *p << '\n'; + } + } From 739dfc5aebceeef121964e1cf5a1d3a362664353 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 7 Jun 2014 23:35:13 -0700 Subject: [PATCH 0395/1866] Rewrites repeat to support temps and bind to lvals More similar to python's repeat, the new version will bind to any lvalue passed in, which I believe to be the expected behavior. This modification changes the semantics of repeat() from it's previous implementation in that the item worked on is no longer a copy of an lvalue that was passed, but a reference to it. --- repeat.hpp | 94 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 32 deletions(-) diff --git a/repeat.hpp b/repeat.hpp index f7438f07..29991c9c 100644 --- a/repeat.hpp +++ b/repeat.hpp @@ -1,49 +1,79 @@ -#ifndef REPEAT_HPP -#define REPEAT_HPP - -#include "iterator_range.hpp" +#ifndef REPEAT_HPP__ +#define REPEAT_HPP__ #include +#include namespace iter { - template - class repeat_iter { + + // must me negative + constexpr int INFINITE_REPEAT = -1; + + template + class Repeater; + + template + Repeater repeat(T&&, int count =INFINITE_REPEAT); + + template + class Repeater { + friend Repeater repeat(T&&, int); private: - const Elem elem; - const size_t until; - size_t start=0; - public: - repeat_iter(const Elem & elem, size_t until) : - elem(elem), - until(until) + T elem; + int count; + + Repeater(T e, int c) + : elem(std::forward(e)), + count{c} { } + public: - repeat_iter & operator++() { - if (this->until != 0) ++start; //no point in repeating 0 times - //so use that to repeat infinitely - return *this; - } + class Iterator { + private: + T& elem; + int count; + public: + Iterator(T& e, int c) + : elem{e}, + count{c} + { } + + // count down to 0 + // INFINITE_REPEAT will be negative, and in that case + // the value is never decremented, it will always compare + // != to an end iterator + Iterator& operator++() { + if (this->count > 0) { + --this->count; + } + return *this; + } - bool operator!=(const repeat_iter &) const { - return this->until == 0 || this->start != this->until; + bool operator!=(const Iterator& other) const { + return this->count != other.count || + &this->elem != &other.elem; + } + + T& operator*() { + return this->elem; + } + }; + + Iterator begin() { + return {this->elem, this->count}; } - Elem operator*() const { - return this->elem; + Iterator end() { + return {this->elem, 0}; } + }; - //-1 causes it to repeat infintely - template - iterator_range> repeat( - const Elem & elem, - size_t until=0) - { - return iterator_range>( - repeat_iter(elem, until), - repeat_iter(elem, until));//just a dummy iter + template + Repeater repeat(T&& e, int count) { + return {std::forward(e), count}; } } -#endif //REPEAT_HPP +#endif //REPEAT_HPP__ From bbc69ea877b85b8b0d123f8112413f603242809b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Jun 2014 11:52:39 -0700 Subject: [PATCH 0396/1866] Replaces chain function with callable object This is in preparation for chain.from_iterable --- chain.hpp | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/chain.hpp b/chain.hpp index 0e57ce09..84dc47e9 100644 --- a/chain.hpp +++ b/chain.hpp @@ -6,16 +6,13 @@ #include namespace iter { - template - class Chained; - - template - Chained chain(Containers&&...); + // rather than a chain function, use a callable object to support + // from_iterable + class ChainMaker; template class Chained { - friend Chained chain( - Container&&, RestContainers&&...); + friend class ChainMaker; template friend class Chained; @@ -84,7 +81,7 @@ namespace iter { }; template class Chained { - friend Chained chain(Container&&); + friend class ChainMaker; template friend class Chained; @@ -132,8 +129,17 @@ namespace iter { } }; - template - Chained chain(Containers&&... containers) { - return {std::forward(containers)...}; + class ChainMaker { + public: + // expose regular call operator to provide usual chain() + template + Chained operator()(Containers&&... cs) const { + return {std::forward(cs)...}; + } + }; + + namespace { + constexpr auto chain = ChainMaker{}; } + } From c898657540dee41ddd26cbb0f8366c2f05cb7737 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Jun 2014 14:46:21 -0700 Subject: [PATCH 0397/1866] Adds test for chain.fromiterable --- tests/.gitignore | 1 + tests/SConstruct | 1 + tests/testchainfromiterable.cpp | 28 ++++++++++++++++++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 tests/testchainfromiterable.cpp diff --git a/tests/.gitignore b/tests/.gitignore index 87ae4e97..7daa7f9d 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -2,6 +2,7 @@ *.swp testaccumulate testchain +testchainfromiterable testcycle testenumerate testrange diff --git a/tests/SConstruct b/tests/SConstruct index 7c0b7cb9..9ca7f7fd 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -38,6 +38,7 @@ progs = Split(''' filterfalse grouper chain + chainfromiterable groupby sorted unique_justseen diff --git a/tests/testchainfromiterable.cpp b/tests/testchainfromiterable.cpp new file mode 100644 index 00000000..f4b6d599 --- /dev/null +++ b/tests/testchainfromiterable.cpp @@ -0,0 +1,28 @@ +#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; +} From 72ce2ceeb46e94032773eb8ad4115f2d3240e7bf Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Jun 2014 15:00:33 -0700 Subject: [PATCH 0398/1866] Adds chain.from_iterable Works with an iterable of iterables, rather than a variadic number of iterables --- chain.hpp | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/chain.hpp b/chain.hpp index 84dc47e9..e5df892d 100644 --- a/chain.hpp +++ b/chain.hpp @@ -1,7 +1,11 @@ +#ifndef CHAIN__HPP__ +#define CHAIN__HPP__ + #include "iterbase.hpp" #include #include +#include #include #include @@ -129,6 +133,75 @@ namespace iter { } }; + template + class ChainedFromIterable { + private: + Container container; + friend class ChainMaker; + ChainedFromIterable(Container container) + : container(std::forward(container)) + { } + + public: + class Iterator { + private: + using SubContainer = iterator_deref; + using SubIter = iterator_type; + + iterator_type top_level_iter; + const iterator_type top_level_end; + std::unique_ptr sub_iter_p; + std::unique_ptr sub_end_p; + public: + Iterator(iterator_type top_iter, + iterator_type top_end) + : top_level_iter{top_iter}, + top_level_end{top_end}, + sub_iter_p{!(top_iter != top_end) ? // iter == end ? + nullptr : new SubIter{std::begin(*top_iter)}}, + sub_end_p{!(top_iter != top_end) ? // iter == end ? + nullptr : new SubIter{std::end(*top_iter)}} + { } + + Iterator& operator++() { + ++*this->sub_iter_p; + if (!(*this->sub_iter_p != *this->sub_end_p)) { + ++this->top_level_iter; + if (this->top_level_iter != this->top_level_end) { + sub_iter_p.reset( + new SubIter{std::begin(*this->top_level_iter)}); + sub_end_p.reset( + new SubIter{std::end(*this->top_level_iter)}); + } else { + sub_iter_p.reset(nullptr); + sub_end_p.reset(nullptr); + } + } + return *this; + } + + + bool operator!=(const Iterator& other) const { + return this->top_level_iter != other.top_level_iter && + (this->sub_iter_p != other.sub_iter_p || + *this->sub_iter_p != *other.sub_iter_p); + } + + iterator_deref> operator*() { + return **this->sub_iter_p; + } + }; + + Iterator begin() { + return {std::begin(this->container), std::end(this->container)}; + } + + Iterator end() { + return {std::end(this->container), std::end(this->container)}; + } + }; + + class ChainMaker { public: // expose regular call operator to provide usual chain() @@ -136,6 +209,13 @@ namespace iter { Chained operator()(Containers&&... cs) const { return {std::forward(cs)...}; } + + // chain.from_iterable + template + ChainedFromIterable from_iterable( + Container&& container) const { + return {std::forward(container)}; + } }; namespace { @@ -143,3 +223,5 @@ namespace iter { } } + +#endif //#define CHAIN__HPP__ From 2fa51679d3e10894ebd88e48243c442630743a83 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Jun 2014 18:10:40 -0700 Subject: [PATCH 0399/1866] Adds chain.from_iterable to README --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.md b/README.md index a5964bef..e62a8cce 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ evaluation wherever possible. [accumulate](#accumulate)
[compress](#compress)
[chain](#chain)
+[chain.from\_iterable](#chain.from_iterable)
[reversed](#reversed)
[slice](#slice)
[sliding_window](#sliding_window)
@@ -352,6 +353,25 @@ for (auto i : chain(empty,vec1,arr1)) { } ``` +chain.from_iterable +------------------- + +Similar to chain, but rather than taking a variadic number of iterables, +it takes an iterable of iterables and chains the contained iterables together. +A simple example is shown below using a vector of vectors to represent +a 2d ragged array, and prints it in row-major order. +```c++ +vector> matrix = { + {1, 2, 3}, + {4, 5}, + {6, 8, 9, 10, 11, 12} +}; + +for (auto i : chain.from_iterable(matrix)) { + cout << i << '\n'; +} +``` + reversed ------- From 5c58485108c2128a56e81419cf25ed1cecddcb98 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Jul 2014 22:40:07 -0700 Subject: [PATCH 0400/1866] replaces SO explosion implementation --- imap.hpp | 101 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 51 insertions(+), 50 deletions(-) diff --git a/imap.hpp b/imap.hpp index 3cc01371..b3e934aa 100644 --- a/imap.hpp +++ b/imap.hpp @@ -8,60 +8,59 @@ namespace iter { - // Everything in detail namespace - // modified from http://stackoverflow.com/questions/10766112/ - // Question by Thomas http://stackoverflow.com/users/115355/thomas - // Answer by Kerrek SB http://stackoverflow.com/users/596781/kerrek-sb - namespace detail - { - // implementation details, users never invoke these directly - template - struct call_impl + 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)...)) { - static auto call(F f, Tuple&& t) -> - decltype(call_impl::call(f, std::forward(t))) - { - return call_impl::call(f, std::forward(t)); - } - }; + // recurse + return Expander::call( + std::forward(f), + std::forward(tup), + std::get(tup), // pull out one element + std::forward(args)...); // everything already expanded + } + }; - template - struct call_impl - { - static auto call(F f, Tuple&& t) -> - decltype(f(std::get(std::forward(t))...)) - { - return f(std::get(std::forward(t))...); - } - }; - - // user invokes this - template - auto call(F f, Tuple&& t) -> - decltype(call_impl::type>::value, - std::tuple_size::type>::value> - ::call(f,std::forward(t))) + template + struct Expander<0, Functor, Tup> { + template + static auto call(Functor&& f, Tup&&, Ts&&... args) + -> decltype(f(std::forward(args)...)) { - typedef typename std::decay::type ttype; - return call_impl::value, - std::tuple_size::value>::call(f,std::forward(t)); + 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(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,9 +101,11 @@ namespace iter { { } auto operator*() const -> - decltype(detail::call(this->map_func, *(this->zipiter))) + decltype(detail::call_with_tuple( + this->map_func, *(this->zipiter))) { - return detail::call(this->map_func, *(this->zipiter)); + return detail::call_with_tuple( + this->map_func, *(this->zipiter)); } Iterator& operator++() { From 7d9cae1a94e40571cc4773e9c994e0dc82659006 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 27 Jul 2014 23:32:21 -0700 Subject: [PATCH 0401/1866] tests combinations with temporary and static array --- tests/testcombinations.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/testcombinations.cpp b/tests/testcombinations.cpp index 2576dc94..1153ed21 100644 --- a/tests/testcombinations.cpp +++ b/tests/testcombinations.cpp @@ -25,9 +25,24 @@ int main() { for (auto j : i ) std::cout << j << " "; std::cout<{1,2,3,4,5}, 3)) { + for (auto j : i ) std::cout << j << " "; + std::cout< Date: Sun, 27 Jul 2014 23:43:07 -0700 Subject: [PATCH 0402/1866] adds support for temporaries to combinations (breaks powerset) --- combinations.hpp | 201 ++++++++++++++++++++++++----------------------- 1 file changed, 101 insertions(+), 100 deletions(-) diff --git a/combinations.hpp b/combinations.hpp index 1ff9a991..6ef85f4d 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -1,125 +1,126 @@ -#ifndef COMBINATIONS_HPP -#define COMBINATIONS_HPP +#ifndef COMBINATIONS_HPP_ +#define COMBINATIONS_HPP_ -#include "iterator_range.hpp" +#include "iterbase.hpp" -#include #include #include #include -#include #include namespace iter { - //Could try having antoher template for container to return (right now it's - //just an std::vector) template - struct combinations_iter; - - template - iterator_range> - combinations(const Container & container, size_t N) { - auto begin = combinations_iter(container,N); - auto end = combinations_iter(container,N); - return - iterator_range>(begin,end); - } - template - iterator_range>> - combinations(std::initializer_list && container, size_t N) { - auto begin = combinations_iter>(container,N); - auto end = combinations_iter>(container,N); - return {begin,end}; - } - template - struct combinations_iter - { + class Combinator { private: - const Container & items; - std::vector indicies; - bool not_done = true; - + Container container; + std::size_t length; public: - //Holy shit look at this typedef - using item_t = typename - std::remove_const< - typename std::remove_reference::type>::type; - combinations_iter(const Container & i, size_t N) : - items(i),indicies(N) - { - if (N == 0) { - not_done = false; - return; - } - size_t inc = 0; - for (auto & iter : indicies) { - if (std::begin(items) + inc != std::end(items)) { - iter = std::begin(items)+inc; - ++inc; - } - else { + Combinator(Container in_container, std::size_t in_length) + : container(std::forward(in_container)), + length{in_length} + { } + + + class Iterator { + private: + Container& items; + std::vector> indicies; + bool not_done = true; + + using item_t = typename + std::remove_const< + typename std::remove_reference>::type>::type; + + public: + Iterator(Container& i, size_t N) + : items(i), + indicies(N) + { + if (N == 0) { not_done = false; - break; + return; + } + size_t inc = 0; + for (auto& iter : indicies) { + if (std::begin(items) + inc != std::end(items)) { + iter = std::begin(items)+inc; + ++inc; + } + else { + not_done = false; + break; + } } } - } - std::vector operator*() const - { - std::vector values; - for (auto i : indicies) { - values.push_back(*i); + + std::vector operator*() { + std::vector values; + for (auto i : indicies) { + values.push_back(*i); + } + return values; } - return values; - } - combinations_iter & - operator++() - { - for (auto iter = indicies.rbegin(); iter != indicies.rend(); ++iter) { - ++(*iter); - //what we have to check here is if the distance between the - //index and the end of indicies is >= the distance between - //the item and end of item - if ((*iter + std::distance(indicies.rbegin(),iter)) == - std::end(items)) { - if ( (iter + 1) != indicies.rend()) { - size_t inc = 1; - for (auto down = iter; down != indicies.rbegin()-1;--down) { - (*down) = (*(iter + 1)) + 1 + inc; - /*if (*down == items.cend()) { - iter = iter + 1; - }*/ - ++inc; + Iterator& operator++() { + for (auto iter = indicies.rbegin(); iter != indicies.rend(); ++iter) { + ++(*iter); + //what we have to check here is if the distance between the + //index and the end of indicies is >= the distance between + //the item and end of item + if ((*iter + std::distance(indicies.rbegin(),iter)) == + std::end(items)) { + if ( (iter + 1) != indicies.rend()) { + size_t inc = 1; + for (auto down = iter; down != indicies.rbegin()-1;--down) { + (*down) = (*(iter + 1)) + 1 + inc; + /*if (*down == items.cend()) { + iter = iter + 1; + }*/ + ++inc; + } + } + else { + not_done = false; + break; } } - else { - not_done = false; - break; - } + else break; + //we break because none of the rest of the items need to + //be incremented } - else break; - //we break because none of the rest of the items need to - //be incremented + return *this; } - return *this; - } - bool operator !=(const combinations_iter &) - { - //because of the way this is done you have to start from the - //begining of the range and end at the end, you could break in - //the middle of the loop though, it's not different from the way - //that python's works - return not_done; - } + bool operator !=(const Iterator&) + { + //because of the way this is done you have to start from the + //begining of the range and end at the end, you could break in + //the middle of the loop though, it's not different from the way + //that python's works + return not_done; + } }; -} -namespace std { + + Iterator begin() { + return {this->container, this->length}; + } + + Iterator end() { + return {this->container, this->length}; + } + }; + template - struct iterator_traits> { - using difference_type = ptrdiff_t; - using iterator_category = input_iterator_tag; - }; + Combinator combinations( + Container&& container, std::size_t length) { + return {std::forward(container), length}; + } + + template + Combinator> combinations( + std::initializer_list il, std::size_t length) { + return {il, length}; + } } -#endif //COMBINATIONS_HPP +#endif //#ifndef COMBINATIONS_HPP_ From 9e77e47f4ef90f4ab9f09ecc964ef5f11586d090 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 28 Jul 2014 20:58:53 -0700 Subject: [PATCH 0403/1866] only combinations() can make a Combinator --- combinations.hpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/combinations.hpp b/combinations.hpp index 6ef85f4d..704363c9 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -9,11 +9,26 @@ #include namespace iter { + template + class Combinator; + + template + Combinator combinations(Container&&, std::size_t); + + template + Combinator> combinations( + std::initializer_list, std::size_t); + template class Combinator { private: Container container; std::size_t length; + + friend Combinator combinations(Container&&,std::size_t); + template + friend Combinator> combinations( + std::initializer_list, std::size_t); public: Combinator(Container in_container, std::size_t in_length) : container(std::forward(in_container)), From 00d981d6960c0faa21cfc40cddb1dff9e63b29ce Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 28 Jul 2014 21:09:54 -0700 Subject: [PATCH 0404/1866] formatting --- combinations.hpp | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/combinations.hpp b/combinations.hpp index 704363c9..31c43ef0 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -44,7 +44,8 @@ namespace iter { using item_t = typename std::remove_const< - typename std::remove_reference>::type>::type; + typename std::remove_reference< + iterator_deref>::type>::type; public: Iterator(Container& i, size_t N) @@ -60,8 +61,7 @@ namespace iter { if (std::begin(items) + inc != std::end(items)) { iter = std::begin(items)+inc; ++inc; - } - else { + } else { not_done = false; break; } @@ -78,41 +78,45 @@ namespace iter { Iterator& operator++() { - for (auto iter = indicies.rbegin(); iter != indicies.rend(); ++iter) { + for (auto iter = indicies.rbegin(); + iter != indicies.rend(); + ++iter) { ++(*iter); - //what we have to check here is if the distance between the - //index and the end of indicies is >= the distance between - //the item and end of item + //what we have to check here is if the distance between + //the index and the end of indicies is >= the distance + //between the item and end of item if ((*iter + std::distance(indicies.rbegin(),iter)) == std::end(items)) { if ( (iter + 1) != indicies.rend()) { size_t inc = 1; - for (auto down = iter; down != indicies.rbegin()-1;--down) { + for (auto down = iter; + down != indicies.rbegin()-1; + --down) { (*down) = (*(iter + 1)) + 1 + inc; /*if (*down == items.cend()) { iter = iter + 1; }*/ ++inc; } - } - else { + } else { not_done = false; break; } + } else { + break; } - else break; - //we break because none of the rest of the items need to - //be incremented + //we break because none of the rest of the items need + //to be incremented } return *this; } bool operator !=(const Iterator&) { - //because of the way this is done you have to start from the - //begining of the range and end at the end, you could break in - //the middle of the loop though, it's not different from the way - //that python's works + //because of the way this is done you have to start from + //the begining of the range and end at the end, you could + //break in the middle of the loop though, it's not + //different from the way that python's works return not_done; } }; From e9bbe4987599175da65d0994d1c45a2b31fed593 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 28 Jul 2014 21:59:47 -0700 Subject: [PATCH 0405/1866] fixes combinations to work despite clang bug --- combinations.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/combinations.hpp b/combinations.hpp index 31c43ef0..a6b4c984 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -57,7 +57,7 @@ namespace iter { return; } size_t inc = 0; - for (auto& iter : indicies) { + for (auto& iter : this->indicies) { if (std::begin(items) + inc != std::end(items)) { iter = std::begin(items)+inc; ++inc; From 3d95314f1b4c9af670038eafb6ecb424b2af7e7f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 30 Jul 2014 22:11:05 -0700 Subject: [PATCH 0406/1866] restores privacy, really --- combinations.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/combinations.hpp b/combinations.hpp index a6b4c984..4853bd73 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -29,12 +29,13 @@ namespace iter { template friend Combinator> combinations( std::initializer_list, std::size_t); - public: + Combinator(Container in_container, std::size_t in_length) : container(std::forward(in_container)), length{in_length} { } + public: class Iterator { private: From 2214b2ccd745a06145ea1fd9fdc860b01f3d1b31 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 1 Aug 2014 13:38:06 -0700 Subject: [PATCH 0407/1866] test with init list and combination size of 1 --- tests/testcombinations.cpp | 5 +++++ tests/testpowerset.cpp | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/tests/testcombinations.cpp b/tests/testcombinations.cpp index 1153ed21..f8c67582 100644 --- a/tests/testcombinations.cpp +++ b/tests/testcombinations.cpp @@ -30,6 +30,11 @@ int main() { for (auto j : i ) std::cout << j << " "; std::cout<{1,2,3,4,5}, 3)) { diff --git a/tests/testpowerset.cpp b/tests/testpowerset.cpp index 10f92c52..d4acbbd9 100644 --- a/tests/testpowerset.cpp +++ b/tests/testpowerset.cpp @@ -10,10 +10,16 @@ int main() { for (auto i : v) std::cout << i << " "; std::cout << std::endl; } + for (auto v : powerset(std::vector{1,2})) { + for (auto i : v) std::cout << i << " "; + std::cout << std::endl; + } for (auto v : powerset({1,2,3,4})) { for (auto i : v) std::cout << i << " "; std::cout << std::endl; } +#if 0 +#endif return 0; } From 651f17216d9d66425d07746df6f700796cf16ea1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 1 Aug 2014 13:47:01 -0700 Subject: [PATCH 0408/1866] powerset supports temps, error with init lists a valgrind error occurs betwee the first two combinations of initializer lists --- powerset.hpp | 128 +++++++++++++++++++++++++++------------------------ 1 file changed, 68 insertions(+), 60 deletions(-) diff --git a/powerset.hpp b/powerset.hpp index 178bd756..d92d419f 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -1,76 +1,84 @@ -#ifndef POWERSET_HPP -#define POWERSET_HPP +#ifndef POWERSET_HPP_ +#define POWERSET_HPP_ -#include "iterator_range.hpp" +#include "iterbase.hpp" #include "combinations.hpp" +#include #include +#include +#include namespace iter { template - struct powerset_iter; + class Powersetter { + private: + Container container; - template - iterator_range> - powerset(const Container & container) - { - auto begin = powerset_iter(container); - auto end = powerset_iter(container); - return iterator_range>(begin,end); - } + public: + Powersetter(Container container) + : container(std::forward(container)) + { } - template - iterator_range>> - powerset(std::initializer_list && container) - { - auto begin = powerset_iter>(container); - auto end = powerset_iter>(container); - return {begin,end}; - } + class Iterator { + private: + std::size_t container_size; + std::size_t list_size = 0; + bool not_done = true; + + using CombinatorType = + decltype(combinations(std::declval(), 0)); + std::vector combinators; + std::vector> inner_iters; + public: + Iterator(Container& container) + : container_size{container.size()} + { + for (std::size_t i = 0; i <= container_size; ++i) { + combinators.push_back(combinations(container, i)); + inner_iters.push_back(std::begin(combinators.back())); + } + } + Iterator& operator++() { + ++inner_iters[list_size]; + if (!(inner_iters[list_size] != inner_iters[list_size])) { + ++list_size; + } + if (container_size < list_size) { + not_done = false; + } - template - struct powerset_iter { - private: - const Container & container; - size_t list_size = 0; - std::vector> inner_iters; - bool not_done = true; - public: - powerset_iter(const Container & c) : - container(c), - inner_iters() - { - for (size_t i = 0; i <= container.size();++i) { - inner_iters.push_back(combinations_iter(container,i)); + return *this; } - } - //default constructor - powerset_iter & operator++() - { - ++(inner_iters[list_size]); - - if (!(inner_iters[list_size] != inner_iters[list_size])) { - ++list_size; - //inner_iter = combinations_iter(container,list_size); - } - if (container.size() < list_size) not_done = false; - return *this; - } - auto operator*() const -> decltype(*inner_iters[list_size]) - { - return *(inner_iters[list_size]); + + auto operator*() -> decltype(*inner_iters[0]) { + return *(inner_iters[list_size]); + } + + bool operator != (const Iterator&) { + return not_done; + } + }; + + Iterator begin() { + return {this->container}; } - bool operator != (const powerset_iter &) { - return not_done; + + Iterator end() { + return {this->container}; } - }; -} -namespace std { + }; + template - struct iterator_traits> { - using difference_type = ptrdiff_t; - using iterator_category = input_iterator_tag; - }; + Powersetter powerset(Container&& container) { + return {std::forward(container)}; + } + + template + Powersetter> powerset( + std::initializer_list il) { + return {il}; + } } -#endif //POWERSET_HPP +#endif // #ifndef POWERSET_HPP_ From fd3ce25749a9da59aec71aa2b5d822e54f964456 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 1 Aug 2014 13:57:22 -0700 Subject: [PATCH 0409/1866] Fixes init list bug, makes iterators faster The creation of the combinators happens at the Powersetter level rather than within the Iterator's constructor. This fixes the error with the initializer_lists. --- powerset.hpp | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/powerset.hpp b/powerset.hpp index d92d419f..e0e7b566 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -10,15 +10,22 @@ #include namespace iter { - template + template (), 0))> class Powersetter { private: Container container; - + + std::vector combinators; public: Powersetter(Container container) : container(std::forward(container)) - { } + { + for (std::size_t i = 0; i <= this->container.size(); ++i) { + combinators.push_back(combinations(this->container, i)); + } + } class Iterator { private: @@ -26,17 +33,16 @@ namespace iter { std::size_t list_size = 0; bool not_done = true; - using CombinatorType = - decltype(combinations(std::declval(), 0)); - std::vector combinators; + std::vector& combinators; std::vector> inner_iters; public: - Iterator(Container& container) - : container_size{container.size()} + Iterator(Container& container, + std::vector& combs) + : container_size{container.size()}, + combinators(combs) { - for (std::size_t i = 0; i <= container_size; ++i) { - combinators.push_back(combinations(container, i)); - inner_iters.push_back(std::begin(combinators.back())); + for (auto& comb : combinators) { + inner_iters.push_back(std::begin(comb)); } } @@ -62,11 +68,11 @@ namespace iter { }; Iterator begin() { - return {this->container}; + return {this->container, this->combinators}; } Iterator end() { - return {this->container}; + return {this->container, this->combinators}; } }; From 7ca955897d09b2e318158ca437e3c1369f842e82 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 1 Aug 2014 15:10:54 -0700 Subject: [PATCH 0410/1866] Removes .size() requirement from powerset argument By just counting the elements when building combinators, there is no need to call .size() on an unknown type Container --- powerset.hpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/powerset.hpp b/powerset.hpp index e0e7b566..815686b9 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -3,7 +3,9 @@ #include "iterbase.hpp" #include "combinations.hpp" +#include "enumerate.hpp" +#include #include #include #include @@ -19,12 +21,17 @@ namespace iter { std::vector combinators; public: - Powersetter(Container container) - : container(std::forward(container)) + Powersetter(Container in_container) + : container(std::forward(in_container)) { - for (std::size_t i = 0; i <= this->container.size(); ++i) { + std::size_t i = 0; + for (auto iter = std::begin(this->container), + end = std::end(this->container); + iter != end; + ++iter, ++i) { combinators.push_back(combinations(this->container, i)); } + combinators.push_back(combinations(this->container, i)); } class Iterator { @@ -36,9 +43,8 @@ namespace iter { std::vector& combinators; std::vector> inner_iters; public: - Iterator(Container& container, - std::vector& combs) - : container_size{container.size()}, + Iterator(std::vector& combs) + : container_size{combs.size() - 1}, combinators(combs) { for (auto& comb : combinators) { @@ -68,11 +74,11 @@ namespace iter { }; Iterator begin() { - return {this->container, this->combinators}; + return {this->combinators}; } Iterator end() { - return {this->container, this->combinators}; + return {this->combinators}; } }; From 597825f2850d08446ffc707de003db762b10a064 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 1 Aug 2014 16:10:59 -0700 Subject: [PATCH 0411/1866] A slight (imo) readbility improvement --- powerset.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/powerset.hpp b/powerset.hpp index 815686b9..ef532917 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -24,14 +24,14 @@ namespace iter { Powersetter(Container in_container) : container(std::forward(in_container)) { - std::size_t i = 0; + combinators.push_back(combinations(this->container, 0)); + std::size_t i = 1; for (auto iter = std::begin(this->container), end = std::end(this->container); iter != end; ++iter, ++i) { combinators.push_back(combinations(this->container, i)); } - combinators.push_back(combinations(this->container, i)); } class Iterator { From cf0ff5a4f836b08eb0a54f9022e0abd15b0c0585 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 1 Aug 2014 17:18:39 -0700 Subject: [PATCH 0412/1866] labels test cases --- tests/testpowerset.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/testpowerset.cpp b/tests/testpowerset.cpp index d4acbbd9..712cae14 100644 --- a/tests/testpowerset.cpp +++ b/tests/testpowerset.cpp @@ -10,11 +10,13 @@ int main() { for (auto i : v) std::cout << i << " "; std::cout << std::endl; } - for (auto v : powerset(std::vector{1,2})) { + 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; } - for (auto v : powerset({1,2,3,4})) { + std::cout << "with initializer_list\n"; + for (auto v : powerset({1,2,3})) { for (auto i : v) std::cout << i << " "; std::cout << std::endl; } From f5ad22a31f9809ec32c8c8958897f304aa7a2bbd Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 Aug 2014 10:50:07 -0700 Subject: [PATCH 0413/1866] breaks line --- combinations.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/combinations.hpp b/combinations.hpp index 4853bd73..65e92425 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -43,8 +43,8 @@ namespace iter { std::vector> indicies; bool not_done = true; - using item_t = typename - std::remove_const< + using item_t = + typename std::remove_const< typename std::remove_reference< iterator_deref>::type>::type; From d6cd3e6b85865a6298894666620523b03344b65b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 Aug 2014 14:54:01 -0700 Subject: [PATCH 0414/1866] adds test with temporary --- tests/testcombinations_with_replacement.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/testcombinations_with_replacement.cpp b/tests/testcombinations_with_replacement.cpp index 40fbad82..213cfd14 100644 --- a/tests/testcombinations_with_replacement.cpp +++ b/tests/testcombinations_with_replacement.cpp @@ -8,17 +8,18 @@ using iter::combinations_with_replacement; int main() { - std::vector v = {1,2,3,4,5}; - for (auto i : combinations_with_replacement(v,40)) { - //std::cout << i << std::endl; + 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< Date: Sat, 2 Aug 2014 14:54:42 -0700 Subject: [PATCH 0415/1866] restores test with init list --- tests/testcombinations_with_replacement.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/testcombinations_with_replacement.cpp b/tests/testcombinations_with_replacement.cpp index 213cfd14..df264335 100644 --- a/tests/testcombinations_with_replacement.cpp +++ b/tests/testcombinations_with_replacement.cpp @@ -19,13 +19,13 @@ int main() { std::cout< Date: Sat, 2 Aug 2014 14:56:58 -0700 Subject: [PATCH 0416/1866] adds support for temporaries --- combinations_with_replacement.hpp | 160 +++++++++++++++++------------- 1 file changed, 89 insertions(+), 71 deletions(-) diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index 07aacf85..fbd6302a 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -2,8 +2,8 @@ #define COMBINATIONS_WITH_REPLACEMENT_HPP #include "iterator_range.hpp" +#include "iterbase.hpp" -#include #include #include @@ -13,12 +13,13 @@ namespace iter { //of items in your combination at runtime, but rather it is a way to view //a list based on the problem your solving, that being said it would be easy //to make it decided at runtime +#if 0 template struct combinations_with_replacement_iter; template iterator_range> - combinations_with_replacement(const Container & container, size_t N) { + combinations_with_replacement(Container & container, std::size_t N) { auto begin = combinations_with_replacement_iter(container, N); auto end = combinations_with_replacement_iter(container, N); return @@ -26,82 +27,99 @@ namespace iter { } template iterator_range>> - combinations_with_replacement(std::initializer_list && container, size_t N) { + combinations_with_replacement(std::initializer_list && container, std::size_t N) { auto begin = combinations_with_replacement_iter>(container, N); auto end = combinations_with_replacement_iter>(container, N); return {begin,end}; } - template - struct combinations_with_replacement_iter - { +#endif + template + class CombinatorWithReplacement { private: - const Container & items; - std::vector indicies; - bool not_done = true; + Container container; + std::size_t length; public: - //Holy shit look at this typedef - using item_t = typename - std::remove_const< - typename std::remove_reference::type>::type; - combinations_with_replacement_iter(const Container & i, size_t N) : - items(i), indicies(N) - { - if (N == 0) { - not_done = false; - return; - } - for (auto & iter : indicies) iter = std::begin(items); - } - //technically should be a dynarray - std::vector operator*()const - { - std::vector values; - for (auto i : indicies) { - values.push_back(*i); - } - return values; - } - - - combinations_with_replacement_iter & - operator++() - { - for (auto iter = indicies.rbegin(); iter != indicies.rend(); ++iter) { - ++(*iter); - if (*iter == std::end(items)) { - if ( (iter + 1) != indicies.rend()) { - for (auto down = iter; down != indicies.rbegin()-1;--down) { - (*down) = (*(iter + 1)) + 1; - } - } - else { - not_done = false; - break; - } - } - else break; - //we break because none of the rest of the items need to - //be incremented - } - return *this; - } - - bool operator !=(const combinations_with_replacement_iter &) - { - //because of the way this is done you have to start from the - //begining of the range and end at the end, you could break in - //the middle of the loop though, it's not different from the way - //that python's works - return not_done; - } - }; -} -namespace std { + CombinatorWithReplacement(Container container, std::size_t n) + : container(std::forward(container)), + length{n} + { } + + class Iterator { + private: + Container& items; + std::vector> indicies; + bool not_done; + + public: + using item_t = + typename std::remove_const< + typename std::remove_reference< + iterator_deref>::type>::type; + + Iterator( + Container& container, std::size_t n) + : items(container), + indicies(n, std::begin(items)), + not_done{n != 0} + { } + + std::vector operator*() + { + std::vector values; + for (auto i : indicies) { + values.push_back(*i); + } + return values; + } + + + Iterator& operator++() { + for (auto iter = indicies.rbegin(); iter != indicies.rend(); ++iter) { + ++(*iter); + if (*iter == std::end(items)) { + if ( (iter + 1) != indicies.rend()) { + for (auto down = iter; down != indicies.rbegin()-1;--down) { + (*down) = (*(iter + 1)) + 1; + } + } + else { + not_done = false; + break; + } + } + else break; + //we break because none of the rest of the items need to + //be incremented + } + return *this; + } + + bool operator !=(const Iterator&) const + { + //because of the way this is done you have to start from the + //begining of the range and end at the end, you could break in + //the middle of the loop though, it's not different from the way + //that python's works + return not_done; + } + }; + + Iterator begin() { + return {this->container, this->length}; + } + + Iterator end() { + return {this->container, 0}; + } + }; + template - struct iterator_traits> { - using difference_type = ptrdiff_t; - using iterator_category = input_iterator_tag; - }; + CombinatorWithReplacement combinations_with_replacement( + Container&& container, std::size_t length) { + return {std::forward(container), length}; + } + } + #endif //COMBINATIONS_WITH_REPLACEMENT_HPP From 59c2f69878688751d872c5e34bc8c80c2a608734 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 Aug 2014 14:57:20 -0700 Subject: [PATCH 0417/1866] adds support for init lists --- combinations_with_replacement.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index fbd6302a..f07846b8 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -120,6 +120,12 @@ namespace iter { return {std::forward(container), length}; } + template + CombinatorWithReplacement> + combinations_with_replacement( + std::initializer_list il, std::size_t length) { + return {il, length}; + } } #endif //COMBINATIONS_WITH_REPLACEMENT_HPP From 74d72af4b24dd63f81b70defcc25674ae78b2a1f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 Aug 2014 15:01:33 -0700 Subject: [PATCH 0418/1866] private value constructor --- combinations_with_replacement.hpp | 42 ++++++++++++++----------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index f07846b8..5738feda 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -8,43 +8,39 @@ #include namespace iter { - //if size isn't passed as template argument would have to switch to vectors - //for everything, generally I would say you don't need to decide the amount - //of items in your combination at runtime, but rather it is a way to view - //a list based on the problem your solving, that being said it would be easy - //to make it decided at runtime -#if 0 + template - struct combinations_with_replacement_iter; + class CombinatorWithReplacement; template - iterator_range> - combinations_with_replacement(Container & container, std::size_t N) { - auto begin = combinations_with_replacement_iter(container, N); - auto end = combinations_with_replacement_iter(container, N); - return - iterator_range>(begin,end); - } - template - iterator_range>> - combinations_with_replacement(std::initializer_list && container, std::size_t N) { - auto begin = combinations_with_replacement_iter>(container, N); - auto end = combinations_with_replacement_iter>(container, N); - return {begin,end}; - } -#endif + CombinatorWithReplacement combinations_with_replacement( + Container&&, std::size_t); + + template + CombinatorWithReplacement> + combinations_with_replacement( + std::initializer_list, std::size_t); + template class CombinatorWithReplacement { private: Container container; std::size_t length; - public: + friend CombinatorWithReplacement + combinations_with_replacement( + Container&& ,std::size_t); + template + friend CombinatorWithReplacement> + combinations_with_replacement( + std::initializer_list, std::size_t); + CombinatorWithReplacement(Container container, std::size_t n) : container(std::forward(container)), length{n} { } + public: class Iterator { private: Container& items; From 7d8ee6de5b41cda60aa1e4ecc8e89b3015fba612 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 Aug 2014 15:06:28 -0700 Subject: [PATCH 0419/1866] adds test with static array --- tests/testcombinations_with_replacement.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/testcombinations_with_replacement.cpp b/tests/testcombinations_with_replacement.cpp index df264335..0f0a194c 100644 --- a/tests/testcombinations_with_replacement.cpp +++ b/tests/testcombinations_with_replacement.cpp @@ -14,22 +14,24 @@ int main() { std::cout<{1,2,3},4)) { for (auto j : i ) std::cout << j << " "; std::cout< Date: Sat, 2 Aug 2014 15:09:44 -0700 Subject: [PATCH 0420/1866] adds some missing includes and formats the source --- combinations_with_replacement.hpp | 35 ++++++++++++++++++------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index 5738feda..f56d7d2b 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -1,11 +1,12 @@ -#ifndef COMBINATIONS_WITH_REPLACEMENT_HPP -#define COMBINATIONS_WITH_REPLACEMENT_HPP +#ifndef COMBINATIONS_WITH_REPLACEMENT_HPP_ +#define COMBINATIONS_WITH_REPLACEMENT_HPP_ -#include "iterator_range.hpp" #include "iterbase.hpp" +#include #include #include +#include namespace iter { @@ -71,32 +72,36 @@ namespace iter { Iterator& operator++() { - for (auto iter = indicies.rbegin(); iter != indicies.rend(); ++iter) { + for (auto iter = indicies.rbegin(); + iter != indicies.rend(); + ++iter) { ++(*iter); if (*iter == std::end(items)) { if ( (iter + 1) != indicies.rend()) { - for (auto down = iter; down != indicies.rbegin()-1;--down) { + for (auto down = iter; + down != indicies.rbegin()-1; + --down) { (*down) = (*(iter + 1)) + 1; } - } - else { + } else { not_done = false; break; } + } else { + //we break because none of the rest of the items + //need to be incremented + break; } - else break; - //we break because none of the rest of the items need to - //be incremented } return *this; } bool operator !=(const Iterator&) const { - //because of the way this is done you have to start from the - //begining of the range and end at the end, you could break in - //the middle of the loop though, it's not different from the way - //that python's works + //because of the way this is done you have to start from + //the begining of the range and end at the end, you + //could break in the middle of the loop though, it's not + //different from the waythat python's works return not_done; } }; @@ -124,4 +129,4 @@ namespace iter { } } -#endif //COMBINATIONS_WITH_REPLACEMENT_HPP +#endif // #ifndef COMBINATIONS_WITH_REPLACEMENT_HPP_ From 203ce5d97626beef09e3b0b58cbfcf3ae262ad73 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 Aug 2014 22:00:20 -0700 Subject: [PATCH 0421/1866] adds test with temporary --- tests/testsliding_window.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/testsliding_window.cpp b/tests/testsliding_window.cpp index 33f0e88d..4b63a9d5 100644 --- a/tests/testsliding_window.cpp +++ b/tests/testsliding_window.cpp @@ -11,5 +11,14 @@ int main() { } std::cout << std::endl; } + + 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; + } + return 0; } From 8d8bdb438bb20102addeb4a0b9e1f93e2a4a050d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 Aug 2014 22:00:48 -0700 Subject: [PATCH 0422/1866] fixes temporary support --- sliding_window.hpp | 143 +++++++++++++++++++++++++++------------------ 1 file changed, 86 insertions(+), 57 deletions(-) diff --git a/sliding_window.hpp b/sliding_window.hpp index a7bea87e..8e81b639 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -1,7 +1,8 @@ -#ifndef SLIDING_WINDOW_HPP -#define SLIDING_WINDOW_HPP +#ifndef SLIDING_WINDOW_HPP_ +#define SLIDING_WINDOW_HPP_ #include "iterator_range.hpp" +#include "iterbase.hpp" #include #include @@ -11,68 +12,96 @@ #include namespace iter { +#if 0 template - struct sliding_window_iter; + struct sliding_window_iter; + template - iterator_range> - sliding_window(Container && container, size_t s) { - auto begin = sliding_window_iter(std::forward(container),s); - auto end = sliding_window_iter(std::forward(container)); - return iterator_range>(begin,end); - } + iterator_range> + sliding_window(Container&& container, std::size_t s) { + auto begin = sliding_window_iter(std::forward(container),s); + auto end = sliding_window_iter(std::forward(container)); + return iterator_range>(begin,end); + } +#endif template - struct sliding_window_iter { - typename - std::conditional::value, - Container&, - const Container &>::type container; - //Container && container; - //using Iterator = decltype(container.begin()); - using Iterator = decltype(std::begin(container)); - std::vector section; - size_t section_size = 0; - sliding_window_iter(Container && c, size_t s) : - container(std::forward(c)),section_size(s) { - size_t i = 0; - for (auto iter = std::begin(container); i < section_size;++iter,++i) { - section.push_back(iter); + class SlidingWindow { + private: + Container container; + std::size_t window_size; + + public: + SlidingWindow(Container container, std::size_t win_sz) + : container(std::forward(container)), + window_size{win_sz} + { } + + class Iterator { + private: + // confusing, but, just makes the type of the vector returned by + // operator*() + using OpDerefElemType = + std::reference_wrapper< + typename std::remove_reference< + iterator_deref>::type>; + using DerefVec = std::vector; + + std::vector> section; + std::size_t section_size = 0; + + public: + Iterator(Container& container, std::size_t s) + : section_size{s} + { + auto iter = std::begin(container); + for (std::size_t i = 0; + i < section_size; + ++iter, ++i) { + section.push_back(iter); + } } - //for (size_t i = 0; i < section_size; ++i) - // section.push_back(container.begin()+i); - } - sliding_window_iter(Container && c) : container(std::forward(c)) - //creates the end iterator - { - section.push_back(std::end(container)); - } - sliding_window_iter & operator++() { - for (auto & iter : section) { - ++iter; - } - return *this; - //std::for_each(section.begin(),section.end(),[](Iterator & i){++i;}); - } - bool operator!=(const sliding_window_iter & rhs) { - return this->section.back() != rhs.section.back(); + // for the end iter + Iterator(Container& container) + : section{std::end(container)}, + section_size{0} + { } + + Iterator& operator++() { + for (auto&& iter : section) { + ++iter; + } + return *this; + } + + bool operator!=(const Iterator& rhs) const { + return this->section.back() != rhs.section.back(); + } + + DerefVec operator*() { + DerefVec vec; + for (auto&& iter : section) { + vec.push_back(*iter); + } + return vec; + } + }; + + Iterator begin() { + return {container, window_size}; } - using Deref_type = std::vector())>::type>>; - Deref_type operator*() - { - Deref_type vec; - for (auto i : section) { - vec.push_back(*i); - } - return vec; + + Iterator end() { + return {container}; } - }; -} -namespace std { + }; + template - struct iterator_traits> { - using difference_type = ptrdiff_t; - using iterator_category = input_iterator_tag; - }; + SlidingWindow sliding_window( + Container&& container, std::size_t window_size) { + return {std::forward(container), window_size}; + } } -#endif //SLIDING_WINDOW_HPP + +#endif //SLIDING_WINDOW_HPP_ From 97c27ecb99245145a87f4fd8eae7252ec4a72953 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 Aug 2014 22:04:35 -0700 Subject: [PATCH 0423/1866] adds test with init list --- tests/testsliding_window.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/testsliding_window.cpp b/tests/testsliding_window.cpp index 4b63a9d5..94b37dab 100644 --- a/tests/testsliding_window.cpp +++ b/tests/testsliding_window.cpp @@ -12,7 +12,7 @@ int main() { std::cout << std::endl; } - for (auto sec : sliding_window(std::vector{1,2,3,4,5,6,7,8,9} ,4)) { + 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; @@ -20,5 +20,12 @@ int main() { std::cout << std::endl; } + 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; + } + return 0; } From 6725ab526809e39cb7316d21420502b88aa1bf62 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 Aug 2014 22:05:17 -0700 Subject: [PATCH 0424/1866] adds support for init lists --- sliding_window.hpp | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/sliding_window.hpp b/sliding_window.hpp index 8e81b639..869c4f90 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -12,19 +12,6 @@ #include namespace iter { -#if 0 - template - struct sliding_window_iter; - - template - iterator_range> - sliding_window(Container&& container, std::size_t s) { - auto begin = sliding_window_iter(std::forward(container),s); - auto end = sliding_window_iter(std::forward(container)); - return iterator_range>(begin,end); - } -#endif - template class SlidingWindow { private: @@ -102,6 +89,12 @@ namespace iter { Container&& container, std::size_t window_size) { return {std::forward(container), window_size}; } + + template + SlidingWindow> sliding_window( + std::initializer_list il, std::size_t window_size) { + return {il, window_size}; + } } #endif //SLIDING_WINDOW_HPP_ From 84a4ddc0b785482929ba42d73b0d9f57645c5588 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 Aug 2014 22:09:20 -0700 Subject: [PATCH 0425/1866] adds test with window size > iterable size --- tests/testsliding_window.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/testsliding_window.cpp b/tests/testsliding_window.cpp index 94b37dab..98ff33f1 100644 --- a/tests/testsliding_window.cpp +++ b/tests/testsliding_window.cpp @@ -1,7 +1,10 @@ #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)) { @@ -27,5 +30,12 @@ int main() { std::cout << std::endl; } + for (auto sec : sliding_window({1,2,3}, 10)) { + for (auto i : sec) { + std::cout << i << " "; + } + std::cout << std::endl; + } + return 0; } From 048db19c27de16ac3bafd0aaa66318742a7f600c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 Aug 2014 22:10:48 -0700 Subject: [PATCH 0426/1866] Covers case where window size > iterable size --- sliding_window.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sliding_window.hpp b/sliding_window.hpp index 869c4f90..4c8b19f3 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -42,8 +42,9 @@ namespace iter { : section_size{s} { auto iter = std::begin(container); + auto end = std::end(container); for (std::size_t i = 0; - i < section_size; + i < section_size && iter != end; ++iter, ++i) { section.push_back(iter); } From 2ef2c8a4755bc4b4d0330e93bf93a22fb88c09df Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 Aug 2014 22:20:39 -0700 Subject: [PATCH 0427/1866] private value ctor --- sliding_window.hpp | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/sliding_window.hpp b/sliding_window.hpp index 4c8b19f3..cc6f640d 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -12,22 +12,40 @@ #include namespace iter { + template + class SlidingWindow; + + template + SlidingWindow sliding_window(Container&&, std::size_t); + + template + SlidingWindow> sliding_window( + std::initializer_list, std::size_t); + template class SlidingWindow { private: Container container; std::size_t window_size; - public: + friend SlidingWindow sliding_window( + Container&&, std::size_t); + + template + friend SlidingWindow> sliding_window( + std::initializer_list, std::size_t); + SlidingWindow(Container container, std::size_t win_sz) : container(std::forward(container)), window_size{win_sz} { } + public: + class Iterator { private: - // confusing, but, just makes the type of the vector returned by - // operator*() + // confusing, but, just makes the type of the vector + // returned by operator*() using OpDerefElemType = std::reference_wrapper< typename std::remove_reference< From 37b502b2ac2e1bd9fbd74d241988fb85967059b6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 Aug 2014 22:24:42 -0700 Subject: [PATCH 0428/1866] adds test with static array --- tests/testsliding_window.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/testsliding_window.cpp b/tests/testsliding_window.cpp index 98ff33f1..16708db7 100644 --- a/tests/testsliding_window.cpp +++ b/tests/testsliding_window.cpp @@ -15,6 +15,7 @@ int main() { 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 << " "; @@ -23,6 +24,7 @@ int main() { 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 << " "; @@ -30,6 +32,7 @@ int main() { 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 << " "; @@ -37,5 +40,14 @@ int main() { 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; } From 8094f723b245c17e27ed6521c1a2157da5402a1e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 3 Aug 2014 12:48:08 -0700 Subject: [PATCH 0429/1866] shortens permutations tests for readability --- tests/testpermutations.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/testpermutations.cpp b/tests/testpermutations.cpp index adeeca06..6ebc03b4 100644 --- a/tests/testpermutations.cpp +++ b/tests/testpermutations.cpp @@ -5,7 +5,7 @@ int main() { using iter::permutations; - std::vector v = {1,2,3,4,5}; + std::vector v = {1,2,3}; for (auto vec : permutations(v)) { for (auto i : vec) { std::cout << i << " "; @@ -27,6 +27,8 @@ int main() { } 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) { From b84a623bbb0d05bfdbe91ff10b948dea9f675434 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 3 Aug 2014 12:48:37 -0700 Subject: [PATCH 0430/1866] reworks permutations overall style --- permutations.hpp | 107 +++++++++++++++++++++++++++-------------------- 1 file changed, 62 insertions(+), 45 deletions(-) diff --git a/permutations.hpp b/permutations.hpp index 1d0e4442..ef6a3dff 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -1,64 +1,81 @@ #ifndef PERMUTATIONS_HPP #define PERMUTATIONS_HPP -#include "iterator_range.hpp" - #include #include #include -namespace iter { - template - struct permutation_iter; - template - iterator_range> - permutations (const Container & container) { - return iterator_range>( - permutation_iter(container), - permutation_iter()); - } - //since initializer_list doesn't have bidir iters this is a hack - //to get it to work by using a vector in its place - template - iterator_range>> - permutations (std::initializer_list && container) { - std::vector begin(std::begin(container),std::end(container)); - return {permutation_iter>(container), - permutation_iter>()}; - } +namespace iter { template - struct permutation_iter - { + class Permuter { + private: Container container; - using Iterator = decltype(std::begin(container)); - bool is_not_last = true; - permutation_iter(){} - permutation_iter(const Container & c) : container(c) - { - //sort first so you can get every permutation - std::sort(std::begin(container),std::end(container)); - } - const Container & operator*() + + public: + // always copy, never move + Permuter(Container in_container) + : container(in_container) { - return container; + std::sort(std::begin(this->container), + std::end(this->container)); } - permutation_iter & operator++() { - is_not_last = std::next_permutation(std::begin(container),std::end(container)); - return *this; + + class Iterator { + private: + Container& container; + bool is_not_last = true; + + public: + Iterator(Container& c) + : container(c) + { } + + Container& operator*() { + return container; + } + + Iterator& operator++() { + is_not_last = + std::next_permutation(std::begin(container), + std::end(container)); + return *this; + } + + bool operator!=(const Iterator&) const { + return is_not_last; + } + + }; + + Iterator begin() { + return {this->container}; } - bool operator!=(const permutation_iter &) { - return is_not_last; + + Iterator end() { + return {this->container}; } - }; -} -namespace std { + + + }; + + // NOTE unlike other itertools, this one copies the input container + // rather than taking a universal ref template - struct iterator_traits> { - using difference_type = ptrdiff_t; - using iterator_category = input_iterator_tag; - }; + Permuter permutations(const Container& container) { + return {container}; + } + + //since initializer_list doesn't have bidir iters this is a hack + //to get it to work by using a vector in its place + template + Permuter> permutations(std::initializer_list il) { + std::vector vec = il; + return {std::move(vec)}; + } + } + #endif //PERMUTATIONS_HPP From 2d6334050a1aaf0cfa083e2f77723145f63fa29f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 3 Aug 2014 15:36:13 -0700 Subject: [PATCH 0431/1866] removes const that was causing me problems --- enumerate.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enumerate.hpp b/enumerate.hpp index f2e63ff2..0bee1f4a 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -85,7 +85,7 @@ namespace iter { index{0} { } - IterYield operator*() const { + IterYield operator*() { return IterYield(this->index, *this->sub_iter); } From eb0a7ad1c17135ac0ada6b56a5e60bd27a9cadf4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 3 Aug 2014 15:39:02 -0700 Subject: [PATCH 0432/1866] removes couts that were still hanging around --- slice.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/slice.hpp b/slice.hpp index 7e1e0d26..fa5f8e2a 100644 --- a/slice.hpp +++ b/slice.hpp @@ -81,8 +81,6 @@ namespace iter { size(this->container))) { this->stop = static_cast(size( this->container)); - std::cout << "stop is too large\n"; - std::cout << "stop is now: " << this->stop << '\n'; } if (this->start < 0) { this->start = 0; From fba04b2b7497b1f7eef7dbe753d008fceddbd2e7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 3 Aug 2014 16:40:57 -0700 Subject: [PATCH 0433/1866] shortens and supports temporaries --- unique_justseen.hpp | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/unique_justseen.hpp b/unique_justseen.hpp index 5729ae23..da759fe9 100644 --- a/unique_justseen.hpp +++ b/unique_justseen.hpp @@ -1,7 +1,8 @@ #ifndef UNIQUE_JUSTSEEN_HPP #define UNIQUE_JUSTSEEN_HPP -#include "filter.hpp" +#include "groupby.hpp" +#include "imap.hpp" #include #include @@ -9,24 +10,17 @@ namespace iter { - //this should be self evident but unique_justseen places the requirement - //on the elements in the container have the != operator overloaded + // 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) - -> Filter,Container> - { - using elem_t = decltype(container.front()); - auto last = container.begin(); - std::function func = [last,container] (elem_t e) mutable - { - if (last == container.begin()) { - return true; - } - else { - return *(++last) != e; - } - }; - return filter(func,std::forward(container)); + auto unique_justseen(Container&& container) { + return imap( + [] (iterator_deref< + decltype( + groupby( + std::forward(container)))>&& gb) + {return *std::begin(gb.second);}, + groupby(std::forward(container))); } } From fadb026defc24dcfebece8895c2ab350c0609fa3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 3 Aug 2014 16:42:50 -0700 Subject: [PATCH 0434/1866] adds test with init list --- tests/testunique_justseen.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/testunique_justseen.cpp b/tests/testunique_justseen.cpp index 7c1dc44e..035b8e67 100644 --- a/tests/testunique_justseen.cpp +++ b/tests/testunique_justseen.cpp @@ -9,6 +9,20 @@ 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 << std::endl; + } + std::cout << '\n'; + + std::cout << "with temporary\n"; + for (auto i : unique_justseen({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'; + return 0; } From f1bd2dc529ff98d337b65a370c646e31e7122a63 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 3 Aug 2014 17:24:09 -0700 Subject: [PATCH 0435/1866] uses custom function object instead of lambda so I can work with c++11. otherwise I'd need a lambda inside the decltype for the trailing return and that's not allowed. I was testing with -std=c++1y at first. --- unique_justseen.hpp | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/unique_justseen.hpp b/unique_justseen.hpp index da759fe9..3a4ad470 100644 --- a/unique_justseen.hpp +++ b/unique_justseen.hpp @@ -1,25 +1,34 @@ #ifndef UNIQUE_JUSTSEEN_HPP #define UNIQUE_JUSTSEEN_HPP +#include "iterbase.hpp" #include "groupby.hpp" #include "imap.hpp" -#include -#include #include +#include +#include namespace iter { + template + struct GroupFrontGetter{ + 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) { - return imap( - [] (iterator_deref< - decltype( - groupby( - std::forward(container)))>&& gb) - {return *std::begin(gb.second);}, + auto unique_justseen(Container&& container) -> + decltype(imap(GroupFrontGetter(container)))>{}, + groupby(std::forward(container)))) { + return imap(GroupFrontGetter(container)))>{}, groupby(std::forward(container))); } } From d4819386a819d22bc2e221de25dbb0fb2923e050 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 3 Aug 2014 17:29:23 -0700 Subject: [PATCH 0436/1866] adds support for init lists --- unique_justseen.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/unique_justseen.hpp b/unique_justseen.hpp index 3a4ad470..878e2e33 100644 --- a/unique_justseen.hpp +++ b/unique_justseen.hpp @@ -31,6 +31,16 @@ namespace iter groupby(std::forward(container)))>{}, 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))); + } } #endif //UNIQUE_JUSTSEEN_HPP From ce54ef0f6774f16c3ef0231dbf6e67ef9e0b45e4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 3 Aug 2014 17:32:45 -0700 Subject: [PATCH 0437/1866] fixes temp test --- tests/testunique_justseen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testunique_justseen.cpp b/tests/testunique_justseen.cpp index 035b8e67..a128fd76 100644 --- a/tests/testunique_justseen.cpp +++ b/tests/testunique_justseen.cpp @@ -13,7 +13,7 @@ int main() { std::cout << '\n'; std::cout << "with temporary\n"; - for (auto i : unique_justseen({1,1,1,2,3,3})) { + for (auto i : unique_justseen(std::vector{1,1,1,2,3,3})) { std::cout << i << " "; } std::cout << '\n'; From d4a310baa039d0d2b969e132c50628de71288eb2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 3 Aug 2014 17:33:27 -0700 Subject: [PATCH 0438/1866] const fix in imap --- imap.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/imap.hpp b/imap.hpp index 3cc01371..31225899 100644 --- a/imap.hpp +++ b/imap.hpp @@ -89,6 +89,7 @@ namespace iter { public: IMap(const IMap&) = default; + IMap(IMap&&) = default; class Iterator { private: @@ -101,7 +102,7 @@ namespace iter { zipiter(zipiter) { } - auto operator*() const -> + auto operator*() -> decltype(detail::call(this->map_func, *(this->zipiter))) { return detail::call(this->map_func, *(this->zipiter)); From ca7c029641e39b7f4c27739d9383c7e525dc9045 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 3 Aug 2014 17:42:11 -0700 Subject: [PATCH 0439/1866] adds test with static array --- tests/testunique_justseen.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/testunique_justseen.cpp b/tests/testunique_justseen.cpp index a128fd76..8f454b6d 100644 --- a/tests/testunique_justseen.cpp +++ b/tests/testunique_justseen.cpp @@ -24,5 +24,12 @@ int main() { } 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; } From a50172d61f14ac633828bdfe7ded9354939234e6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 6 Aug 2014 22:01:26 -0700 Subject: [PATCH 0440/1866] replaces unordered_map with unordered_set --- unique_everseen.hpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/unique_everseen.hpp b/unique_everseen.hpp index 1a67f7e8..96c5a2f6 100644 --- a/unique_everseen.hpp +++ b/unique_everseen.hpp @@ -6,27 +6,29 @@ #include #include #include -#include +#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 template - auto unique_everseen(Container && container) - -> Filter,Container> + auto unique_everseen(Container&& container) + -> Filter,Container> { using elem_t = decltype(container.front()); - std::unordered_map::type,bool> elem_seen; + std::unordered_set::type> elem_seen; std::function func = [elem_seen](elem_t e) mutable //has to be captured by value because it goes out of scope when the //function returns { - if(!elem_seen[e]) { - elem_seen[e] = true; + if (elem_seen.find(e) == std::end(elem_seen)){ + elem_seen.insert(e); return true; + } else { + return false; } - else return false; }; return filter(func,std::forward(container)); } From e0ef7527ed844853ea7c96ffbf059da75705c724 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 6 Aug 2014 22:01:50 -0700 Subject: [PATCH 0441/1866] adds test with temporary --- tests/testunique_everseen.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/testunique_everseen.cpp b/tests/testunique_everseen.cpp index d57674e7..f6565ae2 100644 --- a/tests/testunique_everseen.cpp +++ b/tests/testunique_everseen.cpp @@ -19,5 +19,11 @@ int main() { 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; return 0; } From 4277392ad6fa1a1aa5c81702192c6c763e304cba Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 6 Aug 2014 22:08:27 -0700 Subject: [PATCH 0442/1866] adds test with static array --- tests/testunique_everseen.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/testunique_everseen.cpp b/tests/testunique_everseen.cpp index f6565ae2..78aa41ac 100644 --- a/tests/testunique_everseen.cpp +++ b/tests/testunique_everseen.cpp @@ -25,5 +25,12 @@ int main() { 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'; + return 0; } From a7a188dfb5ed938f9903f139c502b738d79b2a12 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 6 Aug 2014 22:10:45 -0700 Subject: [PATCH 0443/1866] removes .front() requirement on Container --- unique_everseen.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/unique_everseen.hpp b/unique_everseen.hpp index 96c5a2f6..a281b90c 100644 --- a/unique_everseen.hpp +++ b/unique_everseen.hpp @@ -1,6 +1,7 @@ #ifndef UNIQUE_EVERSEEN_HPP #define UNIQUE_EVERSEEN_HPP +#include "iterbase.hpp" #include "filter.hpp" #include @@ -15,9 +16,9 @@ namespace iter //performance checking if it has ever been seen template auto unique_everseen(Container&& container) - -> Filter,Container> + -> Filter)>,Container> { - using elem_t = decltype(container.front()); + using elem_t = iterator_deref; std::unordered_set::type> elem_seen; std::function func = [elem_seen](elem_t e) mutable //has to be captured by value because it goes out of scope when the From a9f7861ca6a71213dfc19d04c20a1dbcc8c1191f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 6 Aug 2014 22:21:34 -0700 Subject: [PATCH 0444/1866] adds test with init list --- tests/testunique_everseen.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/testunique_everseen.cpp b/tests/testunique_everseen.cpp index 78aa41ac..015adb7d 100644 --- a/tests/testunique_everseen.cpp +++ b/tests/testunique_everseen.cpp @@ -32,5 +32,10 @@ int main() { } 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; } From fc556e349930ba0057a318bc552647b3652d452c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 6 Aug 2014 22:21:44 -0700 Subject: [PATCH 0445/1866] adds support for init lists --- unique_everseen.hpp | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/unique_everseen.hpp b/unique_everseen.hpp index a281b90c..77124c8d 100644 --- a/unique_everseen.hpp +++ b/unique_everseen.hpp @@ -20,18 +20,37 @@ namespace iter { using elem_t = iterator_deref; std::unordered_set::type> elem_seen; - std::function func = [elem_seen](elem_t e) mutable + + std::function func = //has to be captured by value because it goes out of scope when the //function returns - { - if (elem_seen.find(e) == std::end(elem_seen)){ - elem_seen.insert(e); - return true; - } else { - return false; - } - }; - return filter(func,std::forward(container)); + [elem_seen](elem_t e) mutable + { + if (elem_seen.find(e) == std::end(elem_seen)){ + elem_seen.insert(e); + return true; + } else { + return false; + } + }; + 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; + } + }; + return filter(func, il); } } From b9b7eae630c5e9a03a5c5c755ffd14bc46aa519e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 8 Aug 2014 22:50:50 -0700 Subject: [PATCH 0446/1866] adds test with temporary --- tests/testzip_longest.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/testzip_longest.cpp b/tests/testzip_longest.cpp index c6c0dc59..339db47a 100644 --- a/tests/testzip_longest.cpp +++ b/tests/testzip_longest.cpp @@ -27,7 +27,11 @@ int main() { for (auto e : zip_longest(ivec, svec)) { std::cout << std::get<0>(e) << std::endl; - //has to deref iter and the optional object + std::cout << std::get<1>(e) << std::endl; + } + + for (auto e : zip_longest("helloworld", ivec)) { + std::cout << std::get<0>(e) << std::endl; std::cout << std::get<1>(e) << std::endl; } } From 12b57f983f6e9b94b61526bb00e2a74e6c9d8ac3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 8 Aug 2014 22:57:11 -0700 Subject: [PATCH 0447/1866] overhauls zip_longest, supports temps --- zip_longest.hpp | 244 ++++++++++++++++++++++++++++++------------------ 1 file changed, 153 insertions(+), 91 deletions(-) diff --git a/zip_longest.hpp b/zip_longest.hpp index b81b1268..f3fd8014 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -1,108 +1,170 @@ -#ifndef ZIP_LONGEST_HPP -#define ZIP_LONGEST_HPP +#ifndef ZIP_LONGEST_HPP_ +#define ZIP_LONGEST_HPP_ -#include "iterator_range.hpp" +#include "iterbase.hpp" #include +#include #include #include -#include + namespace iter { - template - struct zip_longest_iter; - template - iterator_range> - zip_longest(Containers && ... containers) - { - auto begin = - zip_longest_iter(std::forward(containers)...); - auto end = - zip_longest_iter(std::forward(containers)...); - return iterator_range(begin,end); - } - /* - template - auto zip_get(Tuple & t)->decltype(*std::get(t))& - { - return *std::get(t); - } - */ - template - struct zip_longest_iter { - public: - using Iterator = decltype(std::begin(std::declval())); + template + class ZippedLongest; + + template + ZippedLongest zip_longest(Containers&&...); + + template + class ZippedLongest { + static_assert(!std::is_rvalue_reference::value, + "Itertools cannot be templated with rvalue references"); + + friend ZippedLongest zip_longest( + Container&&, RestContainers&&...); + + template + friend class ZippedLongest; + private: - Iterator begin; - const Iterator end; + Container container; + ZippedLongest rest_zipped; + ZippedLongest(Container container, RestContainers&&... rest) + : container(std::forward(container)), + rest_zipped{std::forward(rest)...} + { } public: - zip_longest_iter(Container && c) : - begin(std::begin(c)),end(std::end(c)) {} - - std::tuple())>> - operator*() - { - return std::make_tuple(begin != end ? - boost::optional())>(*begin) - : boost::optional())>()); - } - zip_longest_iter & operator++() { - if(begin!=end)++begin; - return *this; + class Iterator { + private: + using RestIter = + typename ZippedLongest::Iterator; + using OptType = boost::optional>; + + iterator_type iter; + iterator_type end; + RestIter rest_iter; + + public: + Iterator( + iterator_type it, + iterator_type in_end, + const RestIter& rest) + : iter{it}, + end{in_end}, + rest_iter{rest} + { } + + Iterator& operator++() { + if (this->iter != this->end) { + ++this->iter; + } + ++this->rest_iter; + return *this; + } + + bool operator!=(const Iterator& other) const { + return this->iter != other.iter || + this->rest_iter != other.rest_iter; + } + + auto operator*() -> + decltype(std::tuple_cat( + std::tuple{OptType{*this->iter}}, + *this->rest_iter)) + { + if (this->iter != this->end) { + return std::tuple_cat( + std::tuple{OptType{*this->iter}}, + *this->rest_iter); + } else { + return std::tuple_cat( + std::tuple{OptType{}}, + *this->rest_iter); + } + } + }; + + Iterator begin() { + return {std::begin(this->container), + std::end(this->container), + std::begin(this->rest_zipped)}; } - bool operator!=(const zip_longest_iter &) const { - return begin != end; + + Iterator end() { + return {std::end(this->container), + std::end(this->container), + std::end(this->rest_zipped)}; } - }; - template - struct zip_longest_iter { - public: - using Iterator = decltype(std::begin(std::declval())); + }; + + + template + class ZippedLongest { + static_assert(!std::is_rvalue_reference::value, + "Itertools cannot be templated with rvalue references"); + + friend ZippedLongest zip_longest(Container&&); + + template + friend class ZippedLongest; + private: - Iterator begin; - const Iterator end; - zip_longest_iter inner_iter; - + Container container; + ZippedLongest(Container container) + : container(std::forward(container)) + { } + public: - using Elem_t = decltype(*begin); - using tuple_t = - decltype(std::tuple_cat( - std::tuple>(), - *inner_iter)); - - zip_longest_iter(Container && c, Containers && ... containers) : - begin(std::begin(c)), - end(std::end(c)), - inner_iter(std::forward(containers)...) {} - - //this is for returning a tuple of optional - - tuple_t operator*() - { - return std::tuple_cat(std::make_tuple(begin != end - ?boost::optional(*begin) - :boost::optional()),*inner_iter); - } - zip_longest_iter & operator++() { - if (begin != end) ++begin; - ++inner_iter; - return *this; + + class Iterator { + private: + using OptType = boost::optional>; + iterator_type iter; + iterator_type end; + public: + Iterator( + iterator_type it, + iterator_type in_end) + : iter{it}, + end{in_end} + { } + + Iterator& operator++() { + if (this->iter != this->end) { + ++this->iter; + } + return *this; + } + + bool operator!=(const Iterator& other) const { + return this->iter != other.iter; + } + + std::tuple operator*() { + if (this->iter != this->end) { + return std::tuple{OptType{*this->iter}}; + } + return std::tuple{OptType{}}; + } + }; + + Iterator begin() { + return {std::begin(this->container), + std::end(this->container)}; } - bool operator!=(const zip_longest_iter & rhs) const { - return begin != end || (this->inner_iter != rhs.inner_iter); + + Iterator end() { + return {std::end(this->container), + std::end(this->container)}; } - }; -} -//should add reset after the end of a range is reached, just in case someone -//tries to use it again -//this means it's only safe to use the range ONCE, which is fine because of -//the input_iterator_tag -namespace std { - template - struct iterator_traits> { - using difference_type = ptrdiff_t; - using iterator_category = input_iterator_tag; - }; + }; + + template + ZippedLongest zip_longest(Containers&&... containers) { + return {std::forward(containers)...}; + } } -#endif //ZIP_LONGEST_HPP + +#endif // #ifndef ZIP_LONGEST_HPP_ From 9e2f200575ddbd47ea83e4d5e9b8f5ba6a56044d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 8 Aug 2014 23:07:25 -0700 Subject: [PATCH 0448/1866] test with two temps --- tests/testzip_longest.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/testzip_longest.cpp b/tests/testzip_longest.cpp index 339db47a..8ce7753a 100644 --- a/tests/testzip_longest.cpp +++ b/tests/testzip_longest.cpp @@ -30,7 +30,8 @@ int main() { std::cout << std::get<1>(e) << std::endl; } - for (auto e : zip_longest("helloworld", ivec)) { + 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; } From 9d3b1f1ddb50080f22891c3c6ef4fdd2203e4e20 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 8 Aug 2014 23:17:37 -0700 Subject: [PATCH 0449/1866] adds this to cope with clang --- sliding_window.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sliding_window.hpp b/sliding_window.hpp index cc6f640d..516daf9e 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -75,7 +75,7 @@ namespace iter { { } Iterator& operator++() { - for (auto&& iter : section) { + for (auto&& iter : this->section) { ++iter; } return *this; @@ -87,7 +87,7 @@ namespace iter { DerefVec operator*() { DerefVec vec; - for (auto&& iter : section) { + for (auto&& iter : this->section) { vec.push_back(*iter); } return vec; From f1f401b91b6d596cf00411c5466897c21ab3056b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 13 Aug 2014 02:02:10 -0700 Subject: [PATCH 0450/1866] const correctness --- groupby.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index 51360bfb..e26a7e04 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -96,7 +96,7 @@ namespace iter { return this->sub_iter == this->sub_end; } - iterator_deref current() const { + iterator_deref current() { return *this->sub_iter; } @@ -184,7 +184,7 @@ namespace iter { return *this; } - iterator_deref operator*() const { + iterator_deref operator*() { return this->group.owner.current(); } }; From 9832d57bba421a8e3249a71955a171384ab04842 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 13 Aug 2014 02:02:23 -0700 Subject: [PATCH 0451/1866] adds frontgetter overload for lvalues --- unique_justseen.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/unique_justseen.hpp b/unique_justseen.hpp index 878e2e33..eaf81747 100644 --- a/unique_justseen.hpp +++ b/unique_justseen.hpp @@ -17,6 +17,11 @@ namespace iter decltype(*std::begin(gb.second)) { return *std::begin(gb.second); } + + auto operator()(iterator_deref& gb) -> + decltype(*std::begin(gb.second)) { + return *std::begin(gb.second); + } }; From 9236beb24b0ca488c253c735230548e69c84cdf0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 13 Aug 2014 02:05:56 -0700 Subject: [PATCH 0452/1866] ziplongest tests look a lot nicer --- tests/testzip_longest.cpp | 47 +++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/tests/testzip_longest.cpp b/tests/testzip_longest.cpp index 8ce7753a..63dc8fd0 100644 --- a/tests/testzip_longest.cpp +++ b/tests/testzip_longest.cpp @@ -9,14 +9,13 @@ using iter::zip_longest; template -std::ostream & operator<<(std::ostream & o, const boost::optional & opt) { +std::ostream & operator<<(std::ostream & out, const boost::optional& opt) { if (opt) { - std::cout << *opt << std::endl; + out << "Just " << *opt; + } else { + out << "Nothing"; } - else { - std::cout << "Object disengaged of type " << typeid(T).name() << std::endl; - } - return o; + return out; } int main() { @@ -44,39 +43,39 @@ int main() { 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::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::cout << std::get<0>(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::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::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::cout << std::get<0>(e) << ' ' + << std::get<1>(e) << ' ' + << std::get<2>(e) << ' ' << std::get<3>(e) << std::endl; } std::cout<{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::cout << std::get<0>(e) << ' ' + << std::get<1>(e) << ' ' + << std::get<2>(e) << ' ' << std::get<3>(e) << std::endl; } std::cout< Date: Wed, 13 Aug 2014 10:41:42 -0700 Subject: [PATCH 0453/1866] adds Google to list of copyright holders --- LICENSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.md b/LICENSE.md index 3b340456..3d3c6ef0 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,4 +1,4 @@ -Copyright (c) 2013, Ryan Haining, Aaron Josephs +Copyright (c) 2013, Ryan Haining, Aaron Josephs, Google All rights reserved. Redistribution and use in source and binary forms, with or without modification, From 424e8de4c4c9e235152b1709c4b20a63d38aad76 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 17 Aug 2014 14:02:34 -0700 Subject: [PATCH 0454/1866] corrects chainfrom_iterable id --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e62a8cce..570ea278 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ evaluation wherever possible. [accumulate](#accumulate)
[compress](#compress)
[chain](#chain)
-[chain.from\_iterable](#chain.from_iterable)
+[chain.from\_iterable](#chainfrom_iterable)
[reversed](#reversed)
[slice](#slice)
[sliding_window](#sliding_window)
From d3e444fc975157374bce3a4fcea10185aa18efb4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 19 Aug 2014 13:28:21 -0700 Subject: [PATCH 0455/1866] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 570ea278..1602f3af 100644 --- a/README.md +++ b/README.md @@ -432,7 +432,7 @@ for (auto sec : sliding_window(v,4)) { grouper ------ -grouper is very similar to moving section, exception instead of the +grouper is very similar to sliding window, except instead of the section sliding by only 1 it goes the length of the full section. Example usage: From 90c899bbd5e016f9e4ec8a02985866714d8a696e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 20 Aug 2014 11:59:28 -0700 Subject: [PATCH 0456/1866] fixes typo on filterfalse --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1602f3af..7d44c246 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ Similar to filter, but only prints values that are false under the predicate. Prints values not greater than 4: `1 4 3 2 3 2 1 ` ```c++ vector vec{1, 5, 4, 0, 6, 7, 3, 0, 2, 8, 3, 2, 1}; -for (auto i : filter([] (int i) { return i > 4; }, vec)) { +for (auto i : filterfalse([] (int i) { return i > 4; }, vec)) { cout << i <<'\n'; } From 5b157f29435ccbbcd57000f9eeb8c148feee2514 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 24 Aug 2014 00:09:14 -0700 Subject: [PATCH 0457/1866] Adds tests with temporary and array --- tests/testgrouper.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/tests/testgrouper.cpp b/tests/testgrouper.cpp index 50b18554..a1ea0d66 100644 --- a/tests/testgrouper.cpp +++ b/tests/testgrouper.cpp @@ -9,14 +9,22 @@ int main() { std::cout << i << " "; i.get() *= 2; } - std::cout << std::endl; + 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 << " "; - //i.get() = 90; } - std::cout << std::endl; + std::cout << '\n'; } std::vector empty {}; for (auto sec : grouper(empty,3)) { @@ -25,14 +33,13 @@ int main() { std::cout << i << " Shouldn't print\n"; } } - //works when perfect forwarding implemented - /* - for (auto sec : grouper({1,2,3,4,5,6,7,8},3)) { + + int arr[] = {1,2,3,4,5,6,7}; + for (auto sec : grouper(arr, 2)) { for (auto i : sec) { - std::cout << i << " "; + std::cout << i << ' '; } - std::cout << std::endl; + std::cout << '\n'; } - */ return 0; } From ce0dabd8439099a4d16c44e120e92af0abd3fb1a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 24 Aug 2014 00:09:45 -0700 Subject: [PATCH 0458/1866] reworks to support temporaries --- grouper.hpp | 179 +++++++++++++++++++++++++++------------------------- 1 file changed, 93 insertions(+), 86 deletions(-) diff --git a/grouper.hpp b/grouper.hpp index 192fd255..b67f12bb 100644 --- a/grouper.hpp +++ b/grouper.hpp @@ -1,7 +1,7 @@ -#ifndef GROUPER_HPP -#define GROUPER_HPP +#ifndef GROUPER_HPP_ +#define GROUPER_HPP_ -#include "iterator_range.hpp" +#include "iterbase.hpp" #include #include @@ -11,106 +11,113 @@ #include namespace iter { +#if 0 template class grouper_iter; template iterator_range> grouper( - Container && container, size_t s) { + Container && container, std::size_t s) { auto begin = grouper_iter(std::forward(container), s); auto end = grouper_iter(std::forward(container)); return iterator_range>(begin, end); } +#endif template - class grouper_iter { + class Grouper { private: - typename - std::conditional::value, - Container&, - const Container &>::type container; - //Container && container; - //using Iterator = decltype(container.begin()); - using Iterator = decltype(std::begin(container)); - using Deref_type = - std::vector< - std::reference_wrapper< - typename std::remove_reference< - decltype(*std::declval())>::type>>; - - - std::vector group; - - size_t group_size = 0; - bool not_done = true; - - public: - grouper_iter(Container && c, size_t s) : - container(std::forward(c)),group_size(s) - { - // if the group size is 0 or the container is empty produce - // nothing - if (this->group_size == 0 || - !(std::begin(this->container) != std::end(this->container))) { - this->not_done = false; - return; - } - size_t i = 0; - for (auto iter = std::begin(container); i < group_size;++i,++iter) { - group.push_back(iter); - } - //for (size_t i = 0; i < this->group_size; ++i) - // this->group.push_back(this->container.begin() + i); - } + Container container; + std::size_t group_size; + public: + Grouper(Container c, std::size_t sz) + : container(std::forward(c)), + group_size{sz} + { } - //seems like conclassor is same as sliding_window_iter - grouper_iter(Container && c) : - container(std::forward(c)) - { - //creates the end iterator - group.push_back(std::end(container)); - } + class Iterator { + private: + Container& container; + std::vector> group; + std::size_t group_size = 0; + bool not_done = true; - //plan to conditionally check for existence of += - grouper_iter & operator++() { - for (auto & iter : this->group) { - std::advance(iter,this->group_size); - } - return *this; - } - /* - grouper_iter & operator++() { - for (auto & iter : this->group) { - for(size_t i = 0; i < group_size;++i,++iter); - } - return *this; - } - */ - bool operator!=(const grouper_iter &) const { - return this->not_done; - } + using Deref_type = + std::vector< + std::reference_wrapper< + typename std::remove_reference< + iterator_deref>::type>>; + + + public: + Iterator(Container& c, std::size_t s) + : container(c), + group_size(s) + { + // if the group size is 0 or the container is empty produce + // nothing + if (this->group_size == 0 + || (!(std::begin(this->container) + != std::end(this->container)))) { + this->not_done = false; + return; + } + std::size_t i = 0; + for (auto iter = std::begin(container); + i < group_size; + ++i, ++iter) { + group.push_back(iter); + } + } + + //seems like conclassor is same as sliding_window_iter + Iterator(Container& c) + : container(c) + { + //creates the end iterator + group.push_back(std::end(container)); + } - Deref_type operator*() { - Deref_type vec; - for (auto i : this->group) { - if(!(i != std::end(this->container))) { - this->not_done = false; - break; - } - //if the group is at the end the vector will be smaller - else { - vec.push_back(*i); + //plan to conditionally check for existence of += + Iterator & operator++() { + for (auto & iter : this->group) { + std::advance(iter,this->group_size); + } + return *this; } - } - return vec; + + bool operator!=(const Iterator &) const { + return this->not_done; + } + + Deref_type operator*() { + Deref_type vec; + for (auto i : this->group) { + if(!(i != std::end(this->container))) { + this->not_done = false; + break; + } + //if the group is at the end the vector will be smaller + else { + vec.push_back(*i); + } + } + return vec; + } + }; + + Iterator begin() { + return {this->container, group_size}; + } + + Iterator end() { + return {this->container}; } }; -} -namespace std { + template - struct iterator_traits> { - using difference_type = ptrdiff_t; - using iterator_category = input_iterator_tag; - }; + Grouper grouper(Container&& container, std::size_t group_size) { + return {std::forward(container), group_size}; + } } -#endif // ifndef GROUPER_HPP +#endif // #ifndef GROUPER_HPP_ From aed011cf98a550105301f7414b2c902ed7f59496 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 24 Aug 2014 00:12:26 -0700 Subject: [PATCH 0459/1866] removes iter_ideas.txt --- iter_ideas.txt | 56 -------------------------------------------------- 1 file changed, 56 deletions(-) delete mode 100644 iter_ideas.txt diff --git a/iter_ideas.txt b/iter_ideas.txt deleted file mode 100644 index 465fe336..00000000 --- a/iter_ideas.txt +++ /dev/null @@ -1,56 +0,0 @@ -movingsection(Container & container,size_t section_size); -Lets say you have a list - [1,2,3,4,5,6,7,8] -and you want to iterate over 3 elements at a time. You could create three -iterators and incrment them simulatneously, or do something like this. - for (auto tuple : group_x(list,4)) -In this you get the first 4 then all iters are incremeted by 1 each time so -the iterations would be - -1 2 3 -2 3 4 -3 4 5 -4 5 6 -5 6 7 -6 7 8 - - -zip_longest using boost::optional or std::optional when support exists. -useful if a lot of the containers are of different sizes. may want to write -a different zip_get that works better with optional - -Might be a good idea to do a powerset function - -Recipes: -Not all of the recipes are useful, IMO here are the ones I think we should do - ------------------------------------------------------------------------------- -take(n, range) - -takes first n items from range and turns it into its own list - ------------------------------------------------------------------------------- -quantify(range,predicate) - -return amount of times predicate is true - ------------------------------------------------------------------------------- -def flatten(listoflists) - -flattens one level of nesting -would be tricky in c++ but kinda useful - ------------------------------------------------------------------------------- -roundrobin(Containers ... containers) - -takes the first element off in sequence - ------------------------------------------------------------------------------- -unique_everseen(range) - -only shows unique elements - ------------------------------------------------------------------------------- -unique_justseen(range) - -if multiple are the same in a row only display the first one From f2664c1c3734bf6779c3c79bf1f2f215c22df772 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 24 Aug 2014 01:03:14 -0700 Subject: [PATCH 0460/1866] adds test with init list --- tests/testgrouper.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/testgrouper.cpp b/tests/testgrouper.cpp index a1ea0d66..b16ebc98 100644 --- a/tests/testgrouper.cpp +++ b/tests/testgrouper.cpp @@ -41,5 +41,11 @@ int main() { } std::cout << '\n'; } - return 0; + + for (auto sec : grouper({1,2,3,4,5,6,7}, 2)) { + for (auto i : sec) { + std::cout << i << ' '; + } + std::cout << '\n'; + } } From 066d6ea3694c2811d76dd1d00e0fa7ac48b0997c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 24 Aug 2014 01:03:32 -0700 Subject: [PATCH 0461/1866] adds support for init lists --- grouper.hpp | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/grouper.hpp b/grouper.hpp index b67f12bb..314dc1ad 100644 --- a/grouper.hpp +++ b/grouper.hpp @@ -5,25 +5,13 @@ #include #include -#include #include +#include #include #include +#include namespace iter { -#if 0 - template - class grouper_iter; - - template - iterator_range> grouper( - Container && container, std::size_t s) { - auto begin = grouper_iter(std::forward(container), s); - auto end = grouper_iter(std::forward(container)); - return iterator_range>(begin, end); - } -#endif - template class Grouper { private: @@ -119,5 +107,11 @@ namespace iter { Grouper grouper(Container&& container, std::size_t group_size) { return {std::forward(container), group_size}; } + + template + Grouper> grouper( + std::initializer_list il, std::size_t group_size) { + return {il, group_size}; + } } #endif // #ifndef GROUPER_HPP_ From bd52ee1a308481c0a5b4182a7dd2257349979ca1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 24 Aug 2014 01:08:16 -0700 Subject: [PATCH 0462/1866] makes constructor private --- grouper.hpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/grouper.hpp b/grouper.hpp index 314dc1ad..af75ade3 100644 --- a/grouper.hpp +++ b/grouper.hpp @@ -12,17 +12,33 @@ #include namespace iter { + template + class Grouper; + + template + Grouper grouper(Container&&, std::size_t); + + template + Grouper> grouper( + std::initializer_list, std::size_t); + template class Grouper { private: Container container; std::size_t group_size; - public: + Grouper(Container c, std::size_t sz) : container(std::forward(c)), group_size{sz} { } + friend Grouper grouper(Container&&, std::size_t); + template + friend Grouper> grouper( + std::initializer_list, std::size_t); + + public: class Iterator { private: Container& container; From 42d387cd0f26b0aa256f065e9c3117267354675c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 28 Aug 2014 17:59:37 -0400 Subject: [PATCH 0463/1866] adds test with empty zip() --- tests/testzip.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/testzip.cpp b/tests/testzip.cpp index 06e3ebbf..0aa809bd 100644 --- a/tests/testzip.cpp +++ b/tests/testzip.cpp @@ -13,6 +13,8 @@ using iter::zip; int main() { //Ryan's test { + for (auto t : zip()) { } + std::vector ivec{1, 4, 9, 16, 25, 36}; std::vector svec{"hello", "good day", "goodbye"}; From 583db7e91ca60cbdecc7518c4349b7595a520a1d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 28 Aug 2014 18:16:59 -0400 Subject: [PATCH 0464/1866] Supports empty zip(); removes Zipped Instead of specializating on Zipped, specialized for Zipped and lets the normal Zipped class (non-specialized) handle the 0 type case. It makes the template instantiation recursion one level deeper by using an empty base case, but in doing so eliminates the duplicate logic in the one-type specialization, and supports zip() as well. --- zip.hpp | 69 ++++++++++++++++++++++++++------------------------------- 1 file changed, 32 insertions(+), 37 deletions(-) diff --git a/zip.hpp b/zip.hpp index 8f33d099..e4b3bf94 100644 --- a/zip.hpp +++ b/zip.hpp @@ -1,5 +1,5 @@ -#ifndef ZIP__H__ -#define ZIP__H__ +#ifndef ITER_ZIP_HPP_ +#define ITER_ZIP_HPP_ #include "iterbase.hpp" @@ -9,21 +9,22 @@ namespace iter { - template + template class Zipped; template Zipped zip(Containers&&...); + // specialization for at least 1 template argument template - class Zipped { + class Zipped { static_assert(!std::is_rvalue_reference::value, "Itertools cannot be templated with rvalue references"); friend Zipped zip( Container&&, RestContainers&&...); - template + template friend class Zipped; private: @@ -43,6 +44,7 @@ namespace iter { 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} @@ -56,7 +58,8 @@ namespace iter { bool operator!=(const Iterator& other) const { return this->iter != other.iter && - this->rest_iter != other.rest_iter; + (RestIter::is_base_iter || + this->rest_iter != other.rest_iter); } auto operator*() -> @@ -84,53 +87,45 @@ namespace iter { }; - template - class Zipped { - static_assert(!std::is_rvalue_reference::value, - "Itertools cannot be templated with rvalue references"); - - friend Zipped zip(Container&&); - - template - friend class Zipped; - - private: - Container container; - Zipped(Container container) - : container(std::forward(container)) - { } - + // any number of arguments, should only be instantiated if there are 0 + // arguments, since the specialized version gets 1 or more + template + class Zipped { + static_assert(sizeof...(Ts) == 0, + "attempt to instantiate base case with more than 0 types"); public: - class Iterator { - private: - iterator_type iter; public: - Iterator(iterator_type it) - : iter{it} - { } + constexpr static const bool is_base_iter = true; + + Iterator() { } + Iterator(const Iterator&) { } + Iterator& operator=(const Iterator&) { return *this; } Iterator& operator++() { - ++this->iter; return *this; } - bool operator!=(const Iterator& other) const { - return this->iter != other.iter; + // 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>{ - *this->iter}; + std::tuple<> operator*() { + return std::tuple<>{}; } }; Iterator begin() { - return {std::begin(this->container)}; + return {}; } Iterator end() { - return {std::end(this->container)}; + return {}; } }; @@ -140,4 +135,4 @@ namespace iter { } } -#endif //#ifndef ZIP__H__ +#endif // #ifndef ITER_ZIP_HPP_ From 606b4bac6575d542129fa2bc6c28742b7f94702d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 29 Aug 2014 22:59:06 -0400 Subject: [PATCH 0465/1866] replaces general Zipped with specialization instead of Zipped and Zipped, the latter being the empty case. I now have Zipped and Zipped<>. This is a clearer expression of what's actually going on. --- zip.hpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/zip.hpp b/zip.hpp index e4b3bf94..08d2ec1a 100644 --- a/zip.hpp +++ b/zip.hpp @@ -87,12 +87,8 @@ namespace iter { }; - // any number of arguments, should only be instantiated if there are 0 - // arguments, since the specialized version gets 1 or more - template - class Zipped { - static_assert(sizeof...(Ts) == 0, - "attempt to instantiate base case with more than 0 types"); + template <> + class Zipped<> { public: class Iterator { public: @@ -112,7 +108,7 @@ namespace iter { // 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; + return false; } std::tuple<> operator*() { From cdbb9fa30850d67902db361b2d0d9b8089f86c5a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 6 Sep 2014 18:13:24 -0400 Subject: [PATCH 0466/1866] Adds tests with array, temporary, empty product() My laptop died while doing something gitty, so a few commits got lost and I had to put them back in this one. --- tests/testproduct.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/testproduct.cpp b/tests/testproduct.cpp index 94e38944..a07b252b 100644 --- a/tests/testproduct.cpp +++ b/tests/testproduct.cpp @@ -42,5 +42,21 @@ int main() { std::cout << std::get<0>(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; + } + return 0; } From 744c6b9fb5cd7937c760262d297296a64c3e5d37 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 6 Sep 2014 18:14:28 -0400 Subject: [PATCH 0467/1866] Rewritten to support temporaries This is basically zip() modified. --- product.hpp | 248 ++++++++++++++++++++++++++++------------------------ 1 file changed, 136 insertions(+), 112 deletions(-) diff --git a/product.hpp b/product.hpp index e934c362..07bd8849 100644 --- a/product.hpp +++ b/product.hpp @@ -1,124 +1,148 @@ -#ifndef PRODUCT_HPP -#define PRODUCT_HPP -#include "iterator_range.hpp" +#ifndef ITER_PRODUCT_HPP_ +#define ITER_PRODUCT_HPP_ +#include "iterbase.hpp" + +#include #include #include -#include + namespace iter { - template - struct product_iter; - template - iterator_range> - product(const Containers & ... containers) { - auto begin = product_iter(containers...); - auto end = product_iter(containers...); - return iterator_range(begin,end); - } - //template - struct product_iter { - public: - using Iterator = decltype(std::begin(std::declval())); - private: - Iterator begin; - Iterator mover; - const Iterator end; - public: - product_iter(const Container & c) : - begin(std::begin(c)), - mover(std::begin(c)), - end(std::end(c)){} - decltype(std::make_tuple(*mover)) operator*() - //since you can't modify anything anyway it's ok to return a - //tuple of whatever the iterator derefs to - { - return std::make_tuple(*mover); - } - product_iter & operator++() - { - ++mover; - return *this; - } - bool is_not_empty_range() { - return begin != end; - } - bool operator!=(const product_iter&) const - { - return mover != end; - } - bool is_next_iteration() - { - if (!(mover != end)) { - mover = begin; - return true; + template + class Productor; + + template + Productor product(Containers&&...); + + // specialization for at least 1 template argument + template + class Productor { + static_assert(!std::is_rvalue_reference::value, + "Itertools cannot be templated with rvalue references"); + + friend Productor product( + Container&&, RestContainers&&...); + + template + friend class Productor; + + private: + Container container; + Productor rest_products; + Productor(Container container, RestContainers&&... rest) + : container(std::forward(container)), + rest_products{std::forward(rest)...} + { } + + public: + class Iterator { + private: + using RestIter = + typename Productor::Iterator; + + iterator_type iter; + const iterator_type begin; + + RestIter rest_iter; + const RestIter rest_end; + public: + constexpr static const bool is_base_iter = false; + Iterator(iterator_type it, + const RestIter& rest, + const RestIter& in_rest_end) + : iter{it}, + begin{it}, + rest_iter{rest}, + rest_end{in_rest_end} + { } + + void reset() { + this->iter = this->begin; + } + + Iterator& operator++() { + ++this->rest_iter; + if (!(this->rest_iter != this->rest_end)) { + this->rest_iter.reset(); + ++this->iter; + } + return *this; } - else return false; - } - }; - - template - struct product_iter - { - public: - using Iterator = decltype(std::begin(std::declval())); - private: - Iterator begin; - Iterator mover; - const Iterator end; - product_iter inner_iter; - bool no_empty_ranges; - public: - using Tuple_type = decltype(std::tuple_cat(std::make_tuple(*mover),*inner_iter)); - bool is_not_empty_range() { - return begin != end && inner_iter.is_not_empty_range(); - } - product_iter(const Container & c, const Containers & ... containers): - begin(std::begin(c)), - mover(std::begin(c)), - end(std::end(c)), - inner_iter(containers...){ - no_empty_ranges = is_not_empty_range(); + + bool operator!=(const Iterator& other) const { + return this->iter != other.iter && + (RestIter::is_base_iter || + this->rest_iter != other.rest_iter); } - Tuple_type operator*() - { - return std::tuple_cat(std::make_tuple(*mover),*inner_iter); - } - product_iter & operator++() - { - ++inner_iter; - if(inner_iter.is_next_iteration()) + + auto operator*() -> + decltype(std::tuple_cat( + std::tuple>{ + *this->iter}, + *this->rest_iter)) { - ++mover; + return std::tuple_cat( + std::tuple>{ + *this->iter}, + *this->rest_iter); + } + }; + + Iterator begin() { + return {std::begin(this->container), + std::begin(this->rest_products), + std::end(this->rest_products)}; + } + + Iterator end() { + return {std::end(this->container), + std::end(this->rest_products), + std::end(this->rest_products)}; + } + }; + + + template <> + class Productor<> { + public: + class Iterator { + public: + constexpr static const bool is_base_iter = true; + + Iterator() { } + Iterator(const Iterator&) { } + Iterator& operator=(const Iterator&) { return *this; } + + void reset() { } + + Iterator& operator++() { + return *this; } - return *this; - } - bool is_next_iteration() - { - if(!(mover != end)) { - mover = begin; - return true; + + // see note in zip about base case operator!= + bool operator!=(const Iterator&) const { + return false; } - else return false; - } - - bool operator!=(const product_iter&)const - { - return mover != end && no_empty_ranges; - } - //will seg fault if anything but the first is an empty range - //since != only checks the first one - }; -} -namespace std { - template - struct iterator_traits> { - using difference_type = ptrdiff_t; - using iterator_category = input_iterator_tag; - }; + + std::tuple<> operator*() { + return std::tuple<>{}; + } + }; + + Iterator begin() { + return {}; + } + + Iterator end() { + return {}; + } + }; + + template + Productor product(Containers&&... containers) { + return {std::forward(containers)...}; + } } -#endif //PRODUCT_HPP - - +#endif // #ifndef ITER_PRODUCT_HPP_ From 1e0e4a983317ddbfeaf717861fba5bddc249522c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 7 Sep 2014 15:12:58 -0400 Subject: [PATCH 0468/1866] silences unused variable warning --- tests/testzip.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testzip.cpp b/tests/testzip.cpp index 0aa809bd..76a95fd7 100644 --- a/tests/testzip.cpp +++ b/tests/testzip.cpp @@ -13,7 +13,7 @@ using iter::zip; int main() { //Ryan's test { - for (auto t : zip()) { } + for (auto t : zip()) { t=t; } std::vector ivec{1, 4, 9, 16, 25, 36}; std::vector svec{"hello", "good day", "goodbye"}; From 680b7861406638970f26f3d5414413d3cb3c0366 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 7 Sep 2014 15:18:10 -0400 Subject: [PATCH 0469/1866] adds product test with moveonly type --- tests/samples.hpp | 32 ++++++++++++++++++++++++++++++++ tests/testproduct.cpp | 12 ++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 tests/samples.hpp diff --git a/tests/samples.hpp b/tests/samples.hpp new file mode 100644 index 00000000..f98f5c91 --- /dev/null +++ b/tests/samples.hpp @@ -0,0 +1,32 @@ +#ifndef ITERTOOLS_SAMPLE_CLASSES_HPP +#define ITERTOOLS_SAMPLE_CLASSES_HPP + +#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; + } + friend std::ostream& operator<<( + std::ostream& out, const MoveOnly& self) { + return out << self.i; + } + }; + +} +#endif // #ifndef ITERTOOLS_SAMPLE_CLASSES_HPP diff --git a/tests/testproduct.cpp b/tests/testproduct.cpp index a07b252b..7cc07143 100644 --- a/tests/testproduct.cpp +++ b/tests/testproduct.cpp @@ -1,4 +1,7 @@ +#include "samples.hpp" + #include +#include #include #include @@ -7,12 +10,21 @@ using iter::product; //has trouble with empty ranges and more than 2 ranges 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; From 539ebe0ea01593dfef9a002727fa4bcb54ea908d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 7 Sep 2014 15:39:54 -0400 Subject: [PATCH 0470/1866] removes older (and now, wrong) comment --- tests/testproduct.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/testproduct.cpp b/tests/testproduct.cpp index 7cc07143..4af55226 100644 --- a/tests/testproduct.cpp +++ b/tests/testproduct.cpp @@ -8,7 +8,6 @@ #include using iter::product; -//has trouble with empty ranges and more than 2 ranges int main() { std::vector mv; From aecdda1734e388e4476f002e9c72b22a3a191b1a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 7 Sep 2014 15:43:42 -0400 Subject: [PATCH 0471/1866] includes accumulate --- itertools.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/itertools.hpp b/itertools.hpp index 67a59e37..55039902 100644 --- a/itertools.hpp +++ b/itertools.hpp @@ -1,6 +1,7 @@ #ifndef ITERTOOLS_HPP #define ITERTOOLS_HPP +#include "accumulate.hpp" #include "chain.hpp" #include "combinations.hpp" #include "combinations_with_replacement.hpp" @@ -14,7 +15,6 @@ #include "groupby.hpp" #include "grouper.hpp" #include "imap.hpp" -#include "iterator_range.hpp" #include "sliding_window.hpp" #include "permutations.hpp" #include "powerset.hpp" @@ -30,8 +30,6 @@ #include "wrap_iter.hpp" #include "zip.hpp" #include "zip_longest.hpp" -//not sure if should include "iterator_range.hpp" -//since it's already in everything #endif From 85f3a33e31cf1d86bd7bd4abfe0301493f0e2f2e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 7 Sep 2014 15:44:30 -0400 Subject: [PATCH 0472/1866] removes unused include of iterator_range --- sliding_window.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/sliding_window.hpp b/sliding_window.hpp index 516daf9e..202191f1 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -1,7 +1,6 @@ #ifndef SLIDING_WINDOW_HPP_ #define SLIDING_WINDOW_HPP_ -#include "iterator_range.hpp" #include "iterbase.hpp" #include From 1e35b4a09ec8c12049988e7b4e4164eaaa6e9ebd Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 7 Sep 2014 15:44:42 -0400 Subject: [PATCH 0473/1866] removes iterator_range --- iterator_range.hpp | 30 ------------------------------ 1 file changed, 30 deletions(-) delete mode 100644 iterator_range.hpp diff --git a/iterator_range.hpp b/iterator_range.hpp deleted file mode 100644 index f2b4e789..00000000 --- a/iterator_range.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef ITERATOR_RANGE_HPP__ -#define ITERATOR_RANGE_HPP__ - -namespace iter { - - template - class iterator_range { - private: - const Iterator begin_; - const Iterator end_; - - public: - // TODO decide what contstructors should be enabled and disabled - iterator_range(const Iterator & begin, const Iterator & end) : - begin_(begin), - end_(end) - { } - - Iterator begin() const { - return this->begin_; - } - - Iterator end() const { - return this->end_; - } - }; - -} - -#endif //ITERATOR_RANGE_HPP__ From 03b38d316581d3e92155fe89dea53453b08b8c0c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 7 Sep 2014 15:45:16 -0400 Subject: [PATCH 0474/1866] major reworking of testcommand_chains --- tests/testcommand_chains.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/tests/testcommand_chains.cpp b/tests/testcommand_chains.cpp index 07cae5c5..6c5e44c2 100644 --- a/tests/testcommand_chains.cpp +++ b/tests/testcommand_chains.cpp @@ -9,16 +9,14 @@ using namespace iter; template -std::ostream & operator<<(std::ostream & o, const boost::optional & opt) { +std::ostream & operator<<(std::ostream & out, const boost::optional& opt) { if (opt) { - std::cout << *opt; + out << "Just " << *opt; + } else { + out << "Nothing"; } - else { - std::cout << "Object disengaged of type " << typeid(T).name(); - } - return o; + return out; } - int main() { { std::vector vec1{1,2,3,4,5,6}; @@ -30,8 +28,13 @@ int main() { << std::get<1>(t) << std::endl; } } + + std::string str = "hello world"; + std::vector vec = {6, 9, 6, 9}; + for (auto p : enumerate(enumerate(str))) { } + for (auto p : enumerate(zip(str, vec))) { } + std::cout << std::endl; - /* { std::vector vec1{1,2,3,4,5,6}; std::vector vec2{7,8,9,10}; @@ -42,7 +45,6 @@ int main() { << std::get<1>(t) << std::endl; } } - */ std::cout << std::endl; { std::vector vec1{1,2,3,4,5,6}; @@ -53,6 +55,8 @@ int main() { } } std::cout << std::endl; + +#if 0 { std::vector vec1{1,2,3,4,5,6}; std::vector vec2{7,8,9,10}; @@ -61,5 +65,6 @@ int main() { std::cout< Date: Sun, 7 Sep 2014 16:01:23 -0400 Subject: [PATCH 0475/1866] adds command chains back to SConstruct --- tests/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/SConstruct b/tests/SConstruct index 9ca7f7fd..eb1c70a7 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -43,6 +43,7 @@ progs = Split(''' sorted unique_justseen unique_everseen + command_chains ''') From c5e26f4d1d96ea0a438539716fee1c6226c282c4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 7 Sep 2014 17:41:16 -0400 Subject: [PATCH 0476/1866] Makes Enumerable copyable (rule of zero) --- enumerate.hpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 0bee1f4a..15fd605d 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -33,8 +33,6 @@ namespace iter { template class Enumerable { - static_assert(!std::is_rvalue_reference::value, - "Itertools cannot be templated with rvalue references"); private: Container container; @@ -51,15 +49,6 @@ namespace iter { { } public: - Enumerable() = delete; - Enumerable& operator=(const Enumerable&) = delete; - Enumerable(const Enumerable&) = delete; - Enumerable& operator=(Enumerable&&) = delete; - - // movable only - Enumerable(Enumerable&&) = default; - ~Enumerable() = default; - // "yielded" by the Enumerable::Iterator. Has a .index, and a // .element referencing the value yielded by the subiterator class IterYield { From 7c7df597f73500d0deffc8a62903a62f6d02742d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 7 Sep 2014 20:59:28 -0400 Subject: [PATCH 0477/1866] adds test with non-reference-deref'ing iterator Iterator with T operator*() rather than T& operator*() --- tests/samples.hpp | 41 ++++++++++++++++++++++++++++++++++++++ tests/testcombinations.cpp | 16 ++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/tests/samples.hpp b/tests/samples.hpp index f98f5c91..31a7ac0d 100644 --- a/tests/samples.hpp +++ b/tests/samples.hpp @@ -2,6 +2,7 @@ #define ITERTOOLS_SAMPLE_CLASSES_HPP #include +#include namespace itertest { class MoveOnly { @@ -28,5 +29,45 @@ namespace itertest { } }; + class DerefByValue { + private: + static constexpr std::size_t N = 3; + int array[N] = {0}; + 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}; + } + }; } #endif // #ifndef ITERTOOLS_SAMPLE_CLASSES_HPP diff --git a/tests/testcombinations.cpp b/tests/testcombinations.cpp index f8c67582..89be1bc5 100644 --- a/tests/testcombinations.cpp +++ b/tests/testcombinations.cpp @@ -1,3 +1,4 @@ +#include "samples.hpp" #include #include @@ -7,29 +8,42 @@ using iter::combinations; int main() { + itertest::DerefByValue dbv; std::vector v = {1,2,3,4,5}; - //doesn't work with 0 + for (auto i : combinations(v,0)) { for (auto j : i ) std::cout << j << " "; std::cout< Date: Sun, 7 Sep 2014 21:01:07 -0400 Subject: [PATCH 0478/1866] removes random access requirement for combinations Just forward iterator now. --- combinations.hpp | 25 ++++++++++++++----------- iterbase.hpp | 38 +++++++++++++++++++++++++++++++++++--- 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/combinations.hpp b/combinations.hpp index 65e92425..5eed7b04 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -49,18 +49,20 @@ namespace iter { iterator_deref>::type>::type; public: - Iterator(Container& i, size_t N) + Iterator(Container& i, std::size_t n) : items(i), - indicies(N) + indicies(n) { - if (N == 0) { + if (n == 0) { not_done = false; return; } size_t inc = 0; for (auto& iter : this->indicies) { - if (std::begin(items) + inc != std::end(items)) { - iter = std::begin(items)+inc; + auto it = std::begin(this->items); + dumb_advance(it, std::end(this->items), inc); + if (it != std::end(this->items)) { + iter = it; ++inc; } else { not_done = false; @@ -83,20 +85,21 @@ namespace iter { iter != indicies.rend(); ++iter) { ++(*iter); + //what we have to check here is if the distance between //the index and the end of indicies is >= the distance //between the item and end of item - if ((*iter + std::distance(indicies.rbegin(),iter)) == - std::end(items)) { + auto dist = std::distance( + this->indicies.rbegin(),iter); + + if (!(dumb_next(*iter, dist) != + std::end(this->items))) { if ( (iter + 1) != indicies.rend()) { size_t inc = 1; for (auto down = iter; down != indicies.rbegin()-1; --down) { - (*down) = (*(iter + 1)) + 1 + inc; - /*if (*down == items.cend()) { - iter = iter + 1; - }*/ + (*down) = dumb_next(*(iter + 1), 1 + inc); ++inc; } } else { diff --git a/iterbase.hpp b/iterbase.hpp index 85595b3a..00bd88e4 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -1,5 +1,5 @@ -#ifndef ITERBASE__HPP__ -#define ITERBASE__HPP__ +#ifndef ITERBASE_HPP_ +#define ITERBASE_HPP_ // This file consists of utilities used for the generic nature of the @@ -10,8 +10,40 @@ #include #include +#include namespace iter { + // because std::advance assumes a lot and is actually smart, I need a dumb + // version that will work with most things + template + void dumb_advance(InputIt& iter, Distance distance) { + for (Distance i(0); i < distance; ++i) { + ++iter; + } + } + + // iter will not be incremented past end + template + void dumb_advance(InputIt& iter, const InputIt& end, Distance distance=1) { + for (Distance i(0); i < distance && iter != end; ++i) { + ++iter; + } + } + + template + ForwardIt dumb_next(ForwardIt it, Distance distance) { + dumb_advance(it, distance); + return it; + } + + template + ForwardIt dumb_next( + ForwardIt it, const ForwardIt& end, Distance distance=1) { + dumb_advance(it, end, distance); + return it; + } + + // iterator_type is the type of C's iterator template using iterator_type = @@ -35,4 +67,4 @@ namespace iter { decltype(*std::declval&>()); } -#endif // #ifndef ITERBASE__HPP__ +#endif // #ifndef ITERBASE_HPP_ From 7ddcf6e883875cdaff50b0003f9779f54ff99981 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 7 Sep 2014 21:45:48 -0400 Subject: [PATCH 0479/1866] adds test with container of move-only objects --- tests/testcombinations.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/testcombinations.cpp b/tests/testcombinations.cpp index 89be1bc5..4dce1139 100644 --- a/tests/testcombinations.cpp +++ b/tests/testcombinations.cpp @@ -1,5 +1,6 @@ #include "samples.hpp" #include +#include #include #include @@ -9,8 +10,17 @@ 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< Date: Sun, 7 Sep 2014 22:41:26 -0400 Subject: [PATCH 0480/1866] supports containers of move-only in combinations --- combinations.hpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/combinations.hpp b/combinations.hpp index 5eed7b04..c7de09ce 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace iter { template @@ -43,11 +44,17 @@ namespace iter { std::vector> indicies; bool not_done = true; - using item_t = - typename std::remove_const< + // if the iterator dereferences to a reference type, + // then reference_wrapper + // else T + using item_type = + typename std::conditional< + std::is_reference>::value, + std::reference_wrapper< typename std::remove_reference< - iterator_deref>::type>::type; - + iterator_deref>::type>, + typename std::remove_const< + iterator_deref>::type>::type; public: Iterator(Container& i, std::size_t n) : items(i), @@ -71,8 +78,8 @@ namespace iter { } } - std::vector operator*() { - std::vector values; + std::vector operator*() { + std::vector values; for (auto i : indicies) { values.push_back(*i); } From cb42ed1ca5ac80fb2777b30a637d26df8569c16e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 8 Sep 2014 22:06:03 -0400 Subject: [PATCH 0481/1866] test with container of move-only objects --- tests/testcombinations_with_replacement.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/testcombinations_with_replacement.cpp b/tests/testcombinations_with_replacement.cpp index 0f0a194c..2e9ace64 100644 --- a/tests/testcombinations_with_replacement.cpp +++ b/tests/testcombinations_with_replacement.cpp @@ -1,4 +1,6 @@ +#include "samples.hpp" #include +#include #include #include @@ -8,12 +10,23 @@ 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 << " "; From 247f63279990ce6568526a7fbebd4de4524dc6f0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 8 Sep 2014 22:07:09 -0400 Subject: [PATCH 0482/1866] supports containers of move-only objects --- combinations_with_replacement.hpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index f56d7d2b..63914faa 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -4,6 +4,7 @@ #include "iterbase.hpp" #include +#include #include #include #include @@ -49,11 +50,6 @@ namespace iter { bool not_done; public: - using item_t = - typename std::remove_const< - typename std::remove_reference< - iterator_deref>::type>::type; - Iterator( Container& container, std::size_t n) : items(container), @@ -61,9 +57,8 @@ namespace iter { not_done{n != 0} { } - std::vector operator*() - { - std::vector values; + std::vector> operator*() { + std::vector> values; for (auto i : indicies) { values.push_back(*i); } @@ -96,8 +91,7 @@ namespace iter { return *this; } - bool operator !=(const Iterator&) const - { + bool operator !=(const Iterator&) const { //because of the way this is done you have to start from //the begining of the range and end at the end, you //could break in the middle of the loop though, it's not From 4dc6b207ceb53ff9a2696d2686e751e75a21b34c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 8 Sep 2014 22:14:28 -0400 Subject: [PATCH 0483/1866] make distances default to 1 (correctly) --- iterbase.hpp | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/iterbase.hpp b/iterbase.hpp index 00bd88e4..6bea1cfd 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -15,35 +15,34 @@ namespace iter { // because std::advance assumes a lot and is actually smart, I need a dumb // version that will work with most things - template - void dumb_advance(InputIt& iter, Distance distance) { + template + void dumb_advance(InputIt& iter, Distance distance=1) { for (Distance i(0); i < distance; ++i) { ++iter; } } // iter will not be incremented past end - template + template void dumb_advance(InputIt& iter, const InputIt& end, Distance distance=1) { for (Distance i(0); i < distance && iter != end; ++i) { ++iter; } } - template - ForwardIt dumb_next(ForwardIt it, Distance distance) { + template + ForwardIt dumb_next(ForwardIt it, Distance distance=1) { dumb_advance(it, distance); return it; } - template + template ForwardIt dumb_next( ForwardIt it, const ForwardIt& end, Distance distance=1) { dumb_advance(it, end, distance); return it; } - // iterator_type is the type of C's iterator template using iterator_type = @@ -65,6 +64,20 @@ namespace iter { template using reverse_iterator_deref = decltype(*std::declval&>()); + + // For combinatoric functions, if the Containers iterator dereferences + // to a reference, then this is a std::reference_wrapper for that type + // otherwise it's a non-const of that type + template + using collection_item_type = + typename std::conditional< + std::is_reference>::value, + std::reference_wrapper< + typename std::remove_reference< + iterator_deref>::type>, + typename std::remove_const< + iterator_deref>::type>::type; + } #endif // #ifndef ITERBASE_HPP_ From 61d6c9ef58f185e03a06250c1cfd64a44a690530 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 8 Sep 2014 22:18:02 -0400 Subject: [PATCH 0484/1866] adds test with value-dereferencing iterator --- tests/testcombinations_with_replacement.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/testcombinations_with_replacement.cpp b/tests/testcombinations_with_replacement.cpp index 2e9ace64..78b8751e 100644 --- a/tests/testcombinations_with_replacement.cpp +++ b/tests/testcombinations_with_replacement.cpp @@ -21,6 +21,13 @@ int main() { std::cout< Date: Mon, 8 Sep 2014 22:19:58 -0400 Subject: [PATCH 0485/1866] uses the ridiculous typedef from iterbase instead --- combinations.hpp | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/combinations.hpp b/combinations.hpp index c7de09ce..54a2994a 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -44,17 +44,6 @@ namespace iter { std::vector> indicies; bool not_done = true; - // if the iterator dereferences to a reference type, - // then reference_wrapper - // else T - using item_type = - typename std::conditional< - std::is_reference>::value, - std::reference_wrapper< - typename std::remove_reference< - iterator_deref>::type>, - typename std::remove_const< - iterator_deref>::type>::type; public: Iterator(Container& i, std::size_t n) : items(i), @@ -78,8 +67,8 @@ namespace iter { } } - std::vector operator*() { - std::vector values; + std::vector> operator*() { + std::vector> values; for (auto i : indicies) { values.push_back(*i); } From 13d96c1125962fcaf158764b2da4f1f6551a0845 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 8 Sep 2014 22:20:41 -0400 Subject: [PATCH 0486/1866] Supports iterators without random access --- combinations_with_replacement.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index 63914faa..0dc01703 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -71,12 +71,12 @@ namespace iter { iter != indicies.rend(); ++iter) { ++(*iter); - if (*iter == std::end(items)) { + if (!(*iter != std::end(items))) { if ( (iter + 1) != indicies.rend()) { for (auto down = iter; down != indicies.rbegin()-1; --down) { - (*down) = (*(iter + 1)) + 1; + (*down) = dumb_next(*(iter + 1)); } } else { not_done = false; From 09c81a00066b38c7f98d999bc3a182bd8cf2cd11 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 8 Sep 2014 22:25:51 -0400 Subject: [PATCH 0487/1866] adds missing include --- iterbase.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/iterbase.hpp b/iterbase.hpp index 6bea1cfd..15f0a0a0 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -10,6 +10,7 @@ #include #include +#include #include namespace iter { From cfe6e1689e0af76cebf499575ead910b3f0f45c4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 8 Sep 2014 22:26:47 -0400 Subject: [PATCH 0488/1866] removes unused includes of --- combinations.hpp | 1 - combinations_with_replacement.hpp | 1 - 2 files changed, 2 deletions(-) diff --git a/combinations.hpp b/combinations.hpp index 54a2994a..2ae69dff 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -7,7 +7,6 @@ #include #include #include -#include namespace iter { template diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index 0dc01703..ead4319a 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -4,7 +4,6 @@ #include "iterbase.hpp" #include -#include #include #include #include From 01fc9467b4dda18ee91e31f367560c51fb67360f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 8 Sep 2014 22:28:20 -0400 Subject: [PATCH 0489/1866] adds test with container of move-only objects it just works because powerset uses container --- tests/testpowerset.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/testpowerset.cpp b/tests/testpowerset.cpp index 712cae14..31af7a97 100644 --- a/tests/testpowerset.cpp +++ b/tests/testpowerset.cpp @@ -1,4 +1,6 @@ +#include "samples.hpp" #include +#include #include #include @@ -20,8 +22,12 @@ int main() { for (auto i : v) std::cout << i << " "; std::cout << std::endl; } -#if 0 -#endif + + std::cout << "with container of move-only objects\n"; + std::vector mv; + for (auto i : iter::range(3)) { + mv.emplace_back(i); + } return 0; } From 30975801f86eb3a68598f8cdac69b275f394cddb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 8 Sep 2014 22:29:12 -0400 Subject: [PATCH 0490/1866] trailing whitespace...removed --- powerset.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerset.hpp b/powerset.hpp index ef532917..be8e60a8 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -18,7 +18,7 @@ namespace iter { class Powersetter { private: Container container; - + std::vector combinators; public: Powersetter(Container in_container) From 1b83af4fcaf46992f77b533587569041cf80d095 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 8 Sep 2014 22:32:06 -0400 Subject: [PATCH 0491/1866] actually adds the test for move-only objects it really does just work though. heh. --- tests/testpowerset.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/testpowerset.cpp b/tests/testpowerset.cpp index 31af7a97..4a8a93b8 100644 --- a/tests/testpowerset.cpp +++ b/tests/testpowerset.cpp @@ -28,6 +28,9 @@ int main() { 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; + } return 0; } From 81e20b4f3f41ee3051c8e3e31808fc51ecbf193a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 8 Sep 2014 22:33:42 -0400 Subject: [PATCH 0492/1866] adds test with deref-by-value iterator also "just works" --- tests/testpowerset.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/testpowerset.cpp b/tests/testpowerset.cpp index 4a8a93b8..20ca0098 100644 --- a/tests/testpowerset.cpp +++ b/tests/testpowerset.cpp @@ -32,5 +32,13 @@ int main() { 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; } From e9539599b3270bc8938b944d8ace20c996cb7490 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 9 Sep 2014 19:39:33 -0400 Subject: [PATCH 0493/1866] adds test with container of move-only objects --- tests/testpermutations.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/tests/testpermutations.cpp b/tests/testpermutations.cpp index 6ebc03b4..bac92ae3 100644 --- a/tests/testpermutations.cpp +++ b/tests/testpermutations.cpp @@ -1,5 +1,9 @@ -#include +#include "samples.hpp" + #include +#include + +#include #include #include @@ -19,7 +23,7 @@ int main() { std::cout << c << " "; } std::cout << std::endl; - } + } s = "abc"; for (auto vec : permutations(s)) { for (auto c : vec) { @@ -36,5 +40,14 @@ int main() { } std::cout << std::endl; } - return 0; + + 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; + } } From a98f57d2998927b856ea98effa9de060925151cf Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 9 Sep 2014 20:29:41 -0400 Subject: [PATCH 0494/1866] makes MoveOnly less-than comparable --- tests/samples.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/samples.hpp b/tests/samples.hpp index 31a7ac0d..c23fa024 100644 --- a/tests/samples.hpp +++ b/tests/samples.hpp @@ -2,6 +2,7 @@ #define ITERTOOLS_SAMPLE_CLASSES_HPP #include +#include #include namespace itertest { @@ -19,14 +20,22 @@ namespace itertest { 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 { From f0a45816a8020592f7d0d3fb8912121ed77f85ee Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 9 Sep 2014 20:29:54 -0400 Subject: [PATCH 0495/1866] permutations supports containers of move-only --- permutations.hpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/permutations.hpp b/permutations.hpp index ef6a3dff..d9e64a99 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -1,9 +1,11 @@ #ifndef PERMUTATIONS_HPP #define PERMUTATIONS_HPP +#include "iterbase.hpp" #include #include #include +#include namespace iter { @@ -24,29 +26,30 @@ namespace iter { class Iterator { private: - Container& container; + using Permutable = + std::vector>; + Permutable working_set; bool is_not_last = true; public: Iterator(Container& c) - : container(c) + : working_set{std::begin(c), std::end(c)} { } - Container& operator*() { - return container; + Permutable& operator*() { + return working_set; } Iterator& operator++() { is_not_last = - std::next_permutation(std::begin(container), - std::end(container)); + std::next_permutation(std::begin(working_set), + std::end(working_set)); return *this; } bool operator!=(const Iterator&) const { return is_not_last; } - }; Iterator begin() { @@ -63,8 +66,8 @@ namespace iter { // NOTE unlike other itertools, this one copies the input container // rather than taking a universal ref template - Permuter permutations(const Container& container) { - return {container}; + Permuter permutations(Container&& container) { + return {std::forward(container)}; } //since initializer_list doesn't have bidir iters this is a hack From 9bf7264442780b1f7b11391d92756cef852aac7a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 9 Sep 2014 21:15:45 -0400 Subject: [PATCH 0496/1866] adds DerefByValueFancy with random access iterator (it's just a pointer) --- tests/samples.hpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/samples.hpp b/tests/samples.hpp index c23fa024..820d2c1e 100644 --- a/tests/samples.hpp +++ b/tests/samples.hpp @@ -41,7 +41,7 @@ namespace itertest { class DerefByValue { private: static constexpr std::size_t N = 3; - int array[N] = {0}; + int array[N] = {0, 1, 2}; public: DerefByValue() = default; @@ -78,5 +78,21 @@ namespace itertest { 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 From 1004ebfb92323e29c82f1d2c3b97cec87658b99f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 9 Sep 2014 21:16:24 -0400 Subject: [PATCH 0497/1866] adds test with deref-by-value fancy --- tests/testpermutations.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/testpermutations.cpp b/tests/testpermutations.cpp index bac92ae3..0e9b7a06 100644 --- a/tests/testpermutations.cpp +++ b/tests/testpermutations.cpp @@ -50,4 +50,10 @@ int main() { for (auto i : v) std::cout << i << " "; std::cout << std::endl; } + + itertest::DerefByValueFancy dbv; + for (auto v : permutations(dbv)) { + for (auto i : v) std::cout << i << " "; + std::cout << std::endl; + } } From 953b33c8fae7f701675150f599e4721e82692f93 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 9 Sep 2014 21:20:19 -0400 Subject: [PATCH 0498/1866] make permutations work more expectedly instead of always copying, it works like the other itertools. Only the vector of collection_item_types is sorted, rather than the container itself. Additionally, there need not be any strange behavior for initializer_lists anymore. --- permutations.hpp | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/permutations.hpp b/permutations.hpp index d9e64a99..5b5ce4cb 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -1,5 +1,5 @@ -#ifndef PERMUTATIONS_HPP -#define PERMUTATIONS_HPP +#ifndef ITER_PERMUTATIONS_HPP_ +#define ITER_PERMUTATIONS_HPP_ #include "iterbase.hpp" #include @@ -16,13 +16,9 @@ namespace iter { Container container; public: - // always copy, never move Permuter(Container in_container) : container(in_container) - { - std::sort(std::begin(this->container), - std::end(this->container)); - } + { } class Iterator { private: @@ -34,7 +30,10 @@ namespace iter { public: Iterator(Container& c) : working_set{std::begin(c), std::end(c)} - { } + { + std::sort(std::begin(working_set), + std::end(working_set)); + } Permutable& operator*() { return working_set; @@ -63,22 +62,18 @@ namespace iter { }; - // NOTE unlike other itertools, this one copies the input container - // rather than taking a universal ref template Permuter permutations(Container&& container) { return {std::forward(container)}; } - //since initializer_list doesn't have bidir iters this is a hack - //to get it to work by using a vector in its place template - Permuter> permutations(std::initializer_list il) { - std::vector vec = il; - return {std::move(vec)}; + Permuter> permutations( + std::initializer_list il) { + return {il}; } } -#endif //PERMUTATIONS_HPP +#endif // ITER_PERMUTATIONS_HPP_ From 86e6d66bc00859dcff44d51ddaecbcb8259cf4a0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 9 Sep 2014 21:26:32 -0400 Subject: [PATCH 0499/1866] test with normal deref-by-value --- tests/testpermutations.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/testpermutations.cpp b/tests/testpermutations.cpp index 0e9b7a06..a73a2a3b 100644 --- a/tests/testpermutations.cpp +++ b/tests/testpermutations.cpp @@ -51,7 +51,8 @@ int main() { std::cout << std::endl; } - itertest::DerefByValueFancy dbv; + 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; From 16774baf8576e116cb67acb0203145d5eb88ba71 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 9 Sep 2014 21:27:36 -0400 Subject: [PATCH 0500/1866] Permutations supports minimal iterator type I knew it could be done. --- permutations.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/permutations.hpp b/permutations.hpp index 5b5ce4cb..08b24ef0 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -29,8 +29,13 @@ namespace iter { public: Iterator(Container& c) - : working_set{std::begin(c), std::end(c)} { + // done like this instead of using vector ctor with + // two iterators because that causes a substitution + // failure when the iterator is minimal + for (auto&& i : c) { + working_set.emplace_back(i); + } std::sort(std::begin(working_set), std::end(working_set)); } From 8fae67b7448cdc59f72cc454a4655dbb0a423777 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 22 Sep 2014 18:55:21 -0400 Subject: [PATCH 0501/1866] tests producte with range()es --- tests/testproduct.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/testproduct.cpp b/tests/testproduct.cpp index 4af55226..22d132ec 100644 --- a/tests/testproduct.cpp +++ b/tests/testproduct.cpp @@ -68,6 +68,10 @@ int main() { 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; } From 0063f019d1702cfe02f9b1d85cfd3e4157cc5628 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 22 Sep 2014 18:55:27 -0400 Subject: [PATCH 0502/1866] removes const qualifier on step it doesn't really help anything, and prevents the range iterators from being assignable. --- range.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/range.hpp b/range.hpp index 5359379c..53752a3f 100644 --- a/range.hpp +++ b/range.hpp @@ -66,7 +66,7 @@ namespace iter { class Iterator { private: T value; - const T step; + T step; // compare unsigned values bool not_equal_to( From c7e2fc15d4838821752d9f37f52f860054733509 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 23 Sep 2014 21:59:55 -0400 Subject: [PATCH 0503/1866] Adds test with const deref of product --- tests/testcommand_chains.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/testcommand_chains.cpp b/tests/testcommand_chains.cpp index 6c5e44c2..137bc0b2 100644 --- a/tests/testcommand_chains.cpp +++ b/tests/testcommand_chains.cpp @@ -66,5 +66,13 @@ int main() { } } #endif + auto prod_range = iter::product(iter::range(10), iter::range(5)); + + for (auto&& ij: iter::filter( + [](std::tuple 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; } From d0438877e6998a829dcd03619189de602ce3b371 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 23 Sep 2014 22:01:14 -0400 Subject: [PATCH 0504/1866] const correctness for product operator* --- product.hpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/product.hpp b/product.hpp index 07bd8849..40887e64 100644 --- a/product.hpp +++ b/product.hpp @@ -87,6 +87,17 @@ namespace iter { *this->iter}, *this->rest_iter); } + auto operator*() const -> + decltype(std::tuple_cat( + std::tuple>{ + *this->iter}, + *this->rest_iter)) + { + return std::tuple_cat( + std::tuple>{ + *this->iter}, + *this->rest_iter); + } }; Iterator begin() { @@ -125,7 +136,7 @@ namespace iter { return false; } - std::tuple<> operator*() { + std::tuple<> operator*() const { return std::tuple<>{}; } }; From 967c0d4bf5a7ca99a1d55ee137d8d5d96f666bc5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 25 Sep 2014 00:05:05 -0400 Subject: [PATCH 0505/1866] removes extra const in filter --- filter.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/filter.hpp b/filter.hpp index d8986128..50871be9 100644 --- a/filter.hpp +++ b/filter.hpp @@ -1,5 +1,5 @@ -#ifndef FILTER__H__ -#define FILTER__H__ +#ifndef ITER_FILTER_H_ +#define ITER_FILTER_H_ #include "iterbase.hpp" @@ -71,7 +71,7 @@ namespace iter { this->skip_failures(); } - iterator_deref operator*() const { + iterator_deref operator*() { return *this->sub_iter; } @@ -154,4 +154,4 @@ namespace iter { } -#endif //ifndef FILTER__H__ +#endif // #ifndef ITER_FILTER_H_ From 4b5e9a86430b234f32de947a687d7164fb907bcb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 25 Sep 2014 00:06:47 -0400 Subject: [PATCH 0506/1866] removes const product operator* shouldn't have had it it in the first place, it was masking the real issue, in filter --- product.hpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/product.hpp b/product.hpp index 40887e64..4b14353d 100644 --- a/product.hpp +++ b/product.hpp @@ -87,17 +87,6 @@ namespace iter { *this->iter}, *this->rest_iter); } - auto operator*() const -> - decltype(std::tuple_cat( - std::tuple>{ - *this->iter}, - *this->rest_iter)) - { - return std::tuple_cat( - std::tuple>{ - *this->iter}, - *this->rest_iter); - } }; Iterator begin() { From 31872b1b8796362c89b34658128ca82c13cd2521 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 25 Sep 2014 00:11:49 -0400 Subject: [PATCH 0507/1866] fixes include macro --- enumerate.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 15fd605d..52ee3db5 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -1,5 +1,5 @@ -#ifndef ENUMERABLE__H__ -#define ENUMERABLE__H__ +#ifndef ITER_ENUMERATE_H_ +#define ITER_ENUMERATE_H_ #include "iterbase.hpp" @@ -113,4 +113,4 @@ namespace iter { } } -#endif //ifndef ENUMERABLE__H__ +#endif //#ifndef ITER_ENUMERATE_H_ From fce71b6e7623b29349f9a6be2ffd82167b73c887 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 28 Sep 2014 20:41:00 -0400 Subject: [PATCH 0508/1866] 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 0509/1866] 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 0510/1866] 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 0511/1866] 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 0512/1866] 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 0513/1866] 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 14aec8013a0fae127ece1efcf35a63e74b0ee6df Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 29 Sep 2014 21:20:40 -0400 Subject: [PATCH 0514/1866] makes imap infer Zipped type --- imap.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/imap.hpp b/imap.hpp index ad00a193..74e316a7 100644 --- a/imap.hpp +++ b/imap.hpp @@ -73,10 +73,11 @@ namespace iter { // The imap function is the only thing allowed to create a IMap friend IMap imap(MapFunc, Containers&& ...); - using ZippedIterType = iterator_type>; + using ZippedType = decltype(zip(std::declval()...)); + using ZippedIterType = iterator_type; private: MapFunc map_func; - Zipped zipped; + ZippedType zipped; // Value constructor for use only in the imap function IMap(MapFunc map_func, Containers&& ... containers) : From dc7fcd67a40cc9b6ec2464175b8d24ecdb946f97 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 29 Sep 2014 21:21:21 -0400 Subject: [PATCH 0515/1866] 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 90985204a348c843c6d8d3ef6002bc450acf2e77 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 29 Sep 2014 21:21:21 -0400 Subject: [PATCH 0516/1866] removes mutable (idk why it was ever there) --- imap.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/imap.hpp b/imap.hpp index 74e316a7..fd6f0ecc 100644 --- a/imap.hpp +++ b/imap.hpp @@ -1,5 +1,5 @@ -#ifndef IMAP__H__ -#define IMAP__H__ +#ifndef ITER_IMAP_H_ +#define ITER_IMAP_H_ #include "zip.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) : @@ -139,4 +139,4 @@ namespace iter { } -#endif //ifndef IMAP__H__ +#endif // #ifndef ITER_IMAP_H_ From fb8feb024ce2d5746a7c0414ac211e89f577c56f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 29 Sep 2014 21:26:26 -0400 Subject: [PATCH 0517/1866] silences unused variable warnings --- tests/testcommand_chains.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testcommand_chains.cpp b/tests/testcommand_chains.cpp index 137bc0b2..e116f131 100644 --- a/tests/testcommand_chains.cpp +++ b/tests/testcommand_chains.cpp @@ -31,8 +31,8 @@ int main() { std::string str = "hello world"; std::vector vec = {6, 9, 6, 9}; - for (auto p : enumerate(enumerate(str))) { } - for (auto p : enumerate(zip(str, vec))) { } + for (auto p : enumerate(enumerate(str))) { (void)p; } + for (auto p : enumerate(zip(str, vec))) { (void)p; } std::cout << std::endl; { From 034681307b09c4dd74282dd8428378dbdc2c3f89 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 29 Sep 2014 23:12:05 -0400 Subject: [PATCH 0518/1866] 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 3ddb6bd9a532a19c9f4572753c55ec437ce489d0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 12 Oct 2014 19:11:10 -0400 Subject: [PATCH 0519/1866] smarter implementation of reversed() for arrays --- reversed.hpp | 47 +++++++++-------------------------------------- 1 file changed, 9 insertions(+), 38 deletions(-) diff --git a/reversed.hpp b/reversed.hpp index 0cd836e1..dd7a0cc2 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -1,5 +1,5 @@ -#ifndef REVERSE_HPP__ -#define REVERSE_HPP__ +#ifndef ITER_REVERSE_HPP_ +#define ITER_REVERSE_HPP_ #include "iterbase.hpp" @@ -7,7 +7,6 @@ #include namespace iter { - //Forward declarations of Reverser and reversed template class Reverser; @@ -19,11 +18,8 @@ namespace iter { class Reverser { private: Container container; - // The reversed function is the only thing allowed to create a - // Reverser friend Reverser reversed(Container&&); - // Value constructor for use only in the reversed function Reverser(Container container) : container(std::forward(container)) { } @@ -70,10 +66,8 @@ namespace iter { return {std::forward(container)}; } - // // // specialization for statically allocated arrays - // this involves some tricks // template Reverser reversed(T (&)[N]); @@ -98,34 +92,17 @@ namespace iter { class Iterator { private: T *sub_iter; - T *stop; - T *dummy_end; public: - // iter should be the last element in the array - // stop should be the first element - // dummy should be what iter is set to when complete - // the implementation below sets the dummy to one-past- - // the end, since that's the only non-nullptr value that - // the pointer can be set to that is also not a part - // of the actual array - Iterator (T *iter, T *stop, T *dummy) - : sub_iter{iter}, - stop{stop}, - dummy_end{dummy} + Iterator (T *iter) + : sub_iter{iter} { } auto operator*() -> decltype(*array) { - return *this->sub_iter; + return *(this->sub_iter - 1); } Iterator& operator++() { - if (this->sub_iter == this->stop) { - this->sub_iter = this->dummy_end; - } else { - // decrementing the pointer is going forwards - // in the reversed direction - --this->sub_iter; - } + --this->sub_iter; return *this; } @@ -134,18 +111,12 @@ namespace iter { } }; - T *dummy_end() const { - return this->array + N; - } - Iterator begin() { - return {this->array + N - 1, - this->array, - this->dummy_end()}; + return {this->array + N}; } Iterator end() { - return {this->dummy_end(), this->dummy_end(), this->dummy_end()}; + return {this->array}; } }; @@ -157,4 +128,4 @@ namespace iter { } -#endif //REVERSE_HPP__ +#endif //ITER_REVERSE_HPP_ From 327db3415b486176f7889ecd630791d54b944979 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 12 Oct 2014 19:41:08 -0400 Subject: [PATCH 0520/1866] 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 0521/1866] 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 0522/1866] 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 0523/1866] 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 0524/1866] 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 0525/1866] 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 0526/1866] 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 0527/1866] 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 0528/1866] 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 0529/1866] 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 0530/1866] 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 0531/1866] 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 0532/1866] 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 0533/1866] 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 0534/1866] 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 0535/1866] 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 0536/1866] 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 37f7413c8f039920cefe24e664dffdab9833da85 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 28 Oct 2014 16:39:22 -0400 Subject: [PATCH 0537/1866] Grabs PATH from environment --- tests/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/SConstruct b/tests/SConstruct index eb1c70a7..626cb51a 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -2,6 +2,7 @@ import platform import os env = Environment( + ENV = {'PATH' : os.environ['PATH']}, CXX='c++', CXXFLAGS= ['-g', '-Wall', '-Wextra', '-pedantic', '-std=c++11', From 920ec9b6ec912759dc1412193bef26b93bd4285b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 28 Oct 2014 16:39:40 -0400 Subject: [PATCH 0538/1866] removes return 0 --- tests/testchain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testchain.cpp b/tests/testchain.cpp index 99d7a291..19ab374d 100644 --- a/tests/testchain.cpp +++ b/tests/testchain.cpp @@ -11,6 +11,7 @@ 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}; @@ -57,5 +58,4 @@ int main() { std::cout << i << '\n'; } } - return 0; } From 85acb28c3c7ced7aee6617b987b052a5a6f01148 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 28 Oct 2014 16:40:28 -0400 Subject: [PATCH 0539/1866] corrects include guard --- chain.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chain.hpp b/chain.hpp index e5df892d..3d4dc723 100644 --- a/chain.hpp +++ b/chain.hpp @@ -1,5 +1,5 @@ -#ifndef CHAIN__HPP__ -#define CHAIN__HPP__ +#ifndef ITER_CHAIN_HPP_ +#define ITER_CHAIN_HPP_ #include "iterbase.hpp" @@ -224,4 +224,4 @@ namespace iter { } -#endif //#define CHAIN__HPP__ +#endif // #ifndef ITER_CHAIN_HPP_ From 0305423f4079880456fc66a0d78d538bcaaac6a3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 9 Nov 2014 23:46:20 -0500 Subject: [PATCH 0540/1866] 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 dd0f2c40a6e0ec1d65c9ca9553616ccce110346d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 11 Nov 2014 20:20:07 -0500 Subject: [PATCH 0541/1866] range iterator derives std::iterator --- range.hpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/range.hpp b/range.hpp index 53752a3f..f54de39f 100644 --- a/range.hpp +++ b/range.hpp @@ -1,5 +1,5 @@ -#ifndef RANGE__H__ -#define RANGE__H__ +#ifndef ITER_RANGE_H_ +#define ITER_RANGE_H_ // range() for range-based loops with start, stop, and step. // @@ -17,6 +17,7 @@ #include #include +#include namespace iter { @@ -63,7 +64,9 @@ namespace iter { public: Range() = delete; Range(const Range&) = default; - class Iterator { + class Iterator + : public std::iterator + { private: T value; T step; @@ -143,4 +146,4 @@ namespace iter { } } -#endif //ifndef RANGE__H__ +#endif // #ifndef ITER_RANGE_H_ From 300caf936f7ded86b6a3d5579c1942e7dfbee60d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 11 Nov 2014 23:55:01 -0500 Subject: [PATCH 0542/1866] 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 0543/1866] 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 0544/1866] 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 0545/1866] 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 0546/1866] 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 0547/1866] 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 c8b92012a9be224fd80b60bcf0b815ccf2fc9ae4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 13 Nov 2014 09:11:33 -0500 Subject: [PATCH 0548/1866] adds catch.hpp (under boost license) --- catchtest/catch.hpp | 8997 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 8997 insertions(+) create mode 100644 catchtest/catch.hpp diff --git a/catchtest/catch.hpp b/catchtest/catch.hpp new file mode 100644 index 00000000..6b8dfb5e --- /dev/null +++ b/catchtest/catch.hpp @@ -0,0 +1,8997 @@ +/* + * CATCH v1.0 build 53 (master branch) + * Generated: 2014-08-20 08:08:19.533804 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + +#define TWOBLUECUBES_CATCH_HPP_INCLUDED + +// #included from: internal/catch_suppress_warnings.h + +#define TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wglobal-constructors" +#pragma clang diagnostic ignored "-Wvariadic-macros" +#pragma clang diagnostic ignored "-Wc99-extensions" +#pragma clang diagnostic ignored "-Wunused-variable" +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#pragma clang diagnostic ignored "-Wc++98-compat" +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#elif defined __GNUC__ +#pragma GCC diagnostic ignored "-Wvariadic-macros" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpadded" +#endif + +#ifdef CATCH_CONFIG_MAIN +# define CATCH_CONFIG_RUNNER +#endif + +#ifdef CATCH_CONFIG_RUNNER +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// #included from: internal/catch_notimplemented_exception.h +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED + +// #included from: catch_common.h +#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED + +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) + +#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr +#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) + +#include +#include +#include + +// #included from: catch_compiler_capabilities.h +#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED + +// Much of the following code is based on Boost (1.53) + +#ifdef __clang__ + +# if __has_feature(cxx_nullptr) +# define CATCH_CONFIG_CPP11_NULLPTR +# endif + +# if __has_feature(cxx_noexcept) +# define CATCH_CONFIG_CPP11_NOEXCEPT +# endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Borland +#ifdef __BORLANDC__ + +#if (__BORLANDC__ > 0x582 ) +//#define CATCH_CONFIG_SFINAE // Not confirmed +#endif + +#endif // __BORLANDC__ + +//////////////////////////////////////////////////////////////////////////////// +// EDG +#ifdef __EDG_VERSION__ + +#if (__EDG_VERSION__ > 238 ) +//#define CATCH_CONFIG_SFINAE // Not confirmed +#endif + +#endif // __EDG_VERSION__ + +//////////////////////////////////////////////////////////////////////////////// +// Digital Mars +#ifdef __DMC__ + +#if (__DMC__ > 0x840 ) +//#define CATCH_CONFIG_SFINAE // Not confirmed +#endif + +#endif // __DMC__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +#if __GNUC__ < 3 + +#if (__GNUC_MINOR__ >= 96 ) +//#define CATCH_CONFIG_SFINAE +#endif + +#elif __GNUC__ >= 3 + +// #define CATCH_CONFIG_SFINAE // Taking this out completely for now + +#endif // __GNUC__ < 3 + +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) ) + +#define CATCH_CONFIG_CPP11_NULLPTR +#endif + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#if (_MSC_VER >= 1310 ) // (VC++ 7.0+) +//#define CATCH_CONFIG_SFINAE // Not confirmed +#endif + +#endif // _MSC_VER + +// Use variadic macros if the compiler supports them +#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ + ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ + ( defined __GNUC__ && __GNUC__ >= 3 ) || \ + ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) + +#ifndef CATCH_CONFIG_NO_VARIADIC_MACROS +#define CATCH_CONFIG_VARIADIC_MACROS +#endif + +#endif + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// detect language version: +#if (__cplusplus == 201103L) +# define CATCH_CPP11 +# define CATCH_CPP11_OR_GREATER +#elif (__cplusplus >= 201103L) +# define CATCH_CPP11_OR_GREATER +#endif + +// noexcept support: +#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) +# define CATCH_NOEXCEPT noexcept +# define CATCH_NOEXCEPT_IS(x) noexcept(x) +#else +# define CATCH_NOEXCEPT throw() +# define CATCH_NOEXCEPT_IS(x) +#endif + +namespace Catch { + + class NonCopyable { + NonCopyable( NonCopyable const& ); + void operator = ( NonCopyable const& ); + protected: + NonCopyable() {} + virtual ~NonCopyable(); + }; + + class SafeBool { + public: + typedef void (SafeBool::*type)() const; + + static type makeSafe( bool value ) { + return value ? &SafeBool::trueValue : 0; + } + private: + void trueValue() const {} + }; + + template + inline void deleteAll( ContainerT& container ) { + typename ContainerT::const_iterator it = container.begin(); + typename ContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete *it; + } + template + inline void deleteAllValues( AssociativeContainerT& container ) { + typename AssociativeContainerT::const_iterator it = container.begin(); + typename AssociativeContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete it->second; + } + + bool startsWith( std::string const& s, std::string const& prefix ); + bool endsWith( std::string const& s, std::string const& suffix ); + bool contains( std::string const& s, std::string const& infix ); + void toLowerInPlace( std::string& s ); + std::string toLower( std::string const& s ); + std::string trim( std::string const& str ); + + struct pluralise { + pluralise( std::size_t count, std::string const& label ); + + friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); + + std::size_t m_count; + std::string m_label; + }; + + struct SourceLineInfo { + + SourceLineInfo(); + SourceLineInfo( char const* _file, std::size_t _line ); + SourceLineInfo( SourceLineInfo const& other ); +# ifdef CATCH_CPP11_OR_GREATER + SourceLineInfo( SourceLineInfo && ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo& operator = ( SourceLineInfo && ) = default; +# endif + bool empty() const; + bool operator == ( SourceLineInfo const& other ) const; + + std::string file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // This is just here to avoid compiler warnings with macro constants and boolean literals + inline bool isTrue( bool value ){ return value; } + inline bool alwaysTrue() { return true; } + inline bool alwaysFalse() { return false; } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() { + return std::string(); + } + }; + template + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) +#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); + +#include + +namespace Catch { + + class NotImplementedException : public std::exception + { + public: + NotImplementedException( SourceLineInfo const& lineInfo ); + NotImplementedException( NotImplementedException const& ) {} + + virtual ~NotImplementedException() CATCH_NOEXCEPT {} + + virtual const char* what() const CATCH_NOEXCEPT; + + private: + std::string m_what; + SourceLineInfo m_lineInfo; + }; + +} // end namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) + +// #included from: internal/catch_context.h +#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED + +// #included from: catch_interfaces_generators.h +#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED + +#include + +namespace Catch { + + struct IGeneratorInfo { + virtual ~IGeneratorInfo(); + virtual bool moveNext() = 0; + virtual std::size_t getCurrentIndex() const = 0; + }; + + struct IGeneratorsForTest { + virtual ~IGeneratorsForTest(); + + virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; + virtual bool moveNext() = 0; + }; + + IGeneratorsForTest* createGeneratorsForTest(); + +} // end namespace Catch + +// #included from: catch_ptr.hpp +#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + // An intrusive reference counting smart pointer. + // T must implement addRef() and release() methods + // typically implementing the IShared interface + template + class Ptr { + public: + Ptr() : m_p( NULL ){} + Ptr( T* p ) : m_p( p ){ + if( m_p ) + m_p->addRef(); + } + Ptr( Ptr const& other ) : m_p( other.m_p ){ + if( m_p ) + m_p->addRef(); + } + ~Ptr(){ + if( m_p ) + m_p->release(); + } + void reset() { + if( m_p ) + m_p->release(); + m_p = NULL; + } + Ptr& operator = ( T* p ){ + Ptr temp( p ); + swap( temp ); + return *this; + } + Ptr& operator = ( Ptr const& other ){ + Ptr temp( other ); + swap( temp ); + return *this; + } + void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } + T* get() { return m_p; } + const T* get() const{ return m_p; } + T& operator*() const { return *m_p; } + T* operator->() const { return m_p; } + bool operator !() const { return m_p == NULL; } + operator SafeBool::type() const { return SafeBool::makeSafe( m_p != NULL ); } + + private: + T* m_p; + }; + + struct IShared : NonCopyable { + virtual ~IShared(); + virtual void addRef() const = 0; + virtual void release() const = 0; + }; + + template + struct SharedImpl : T { + + SharedImpl() : m_rc( 0 ){} + + virtual void addRef() const { + ++m_rc; + } + virtual void release() const { + if( --m_rc == 0 ) + delete this; + } + + mutable unsigned int m_rc; + }; + +} // end namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#include +#include +#include + +namespace Catch { + + class TestCase; + class Stream; + struct IResultCapture; + struct IRunner; + struct IGeneratorsForTest; + struct IConfig; + + struct IContext + { + virtual ~IContext(); + + virtual IResultCapture* getResultCapture() = 0; + virtual IRunner* getRunner() = 0; + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; + virtual bool advanceGeneratorsForCurrentTest() = 0; + virtual Ptr getConfig() const = 0; + }; + + struct IMutableContext : IContext + { + virtual ~IMutableContext(); + virtual void setResultCapture( IResultCapture* resultCapture ) = 0; + virtual void setRunner( IRunner* runner ) = 0; + virtual void setConfig( Ptr const& config ) = 0; + }; + + IContext& getCurrentContext(); + IMutableContext& getCurrentMutableContext(); + void cleanUpContext(); + Stream createStream( std::string const& streamName ); + +} + +// #included from: internal/catch_test_registry.hpp +#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED + +// #included from: catch_interfaces_testcase.h +#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED + +#include + +namespace Catch { + + class TestSpec; + + struct ITestCase : IShared { + virtual void invoke () const = 0; + protected: + virtual ~ITestCase(); + }; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector const& getAllTests() const = 0; + virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases ) const = 0; + + }; +} + +namespace Catch { + +template +class MethodTestCase : public SharedImpl { + +public: + MethodTestCase( void (C::*method)() ) : m_method( method ) {} + + virtual void invoke() const { + C obj; + (obj.*m_method)(); + } + +private: + virtual ~MethodTestCase() {} + + void (C::*m_method)(); +}; + +typedef void(*TestFunction)(); + +struct NameAndDesc { + NameAndDesc( const char* _name = "", const char* _description= "" ) + : name( _name ), description( _description ) + {} + + const char* name; + const char* description; +}; + +struct AutoReg { + + AutoReg( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + + template + AutoReg( void (C::*method)(), + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + registerTestCase( new MethodTestCase( method ), + className, + nameAndDesc, + lineInfo ); + } + + void registerTestCase( ITestCase* testCase, + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ); + + ~AutoReg(); + +private: + AutoReg( AutoReg const& ); + void operator= ( AutoReg const& ); +}; + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( ... ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + +#else + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + +#endif + +// #included from: internal/catch_capture.hpp +#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED + +// #included from: catch_result_builder.h +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED + +// #included from: catch_result_type.h +#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED + +namespace Catch { + + // ResultWas::OfType enum + struct ResultWas { enum OfType { + Unknown = -1, + Ok = 0, + Info = 1, + Warning = 2, + + FailureBit = 0x10, + + ExpressionFailed = FailureBit | 1, + ExplicitFailure = FailureBit | 2, + + Exception = 0x100 | FailureBit, + + ThrewException = Exception | 1, + DidntThrowException = Exception | 2 + + }; }; + + inline bool isOk( ResultWas::OfType resultType ) { + return ( resultType & ResultWas::FailureBit ) == 0; + } + inline bool isJustInfo( int flags ) { + return flags == ResultWas::Info; + } + + // ResultDisposition::Flags enum + struct ResultDisposition { enum Flags { + Normal = 0x00, + + ContinueOnFailure = 0x01, // Failures fail test, but execution continues + FalseTest = 0x02, // Prefix expression with ! + SuppressFail = 0x04 // Failures are reported but do not fail the test + }; }; + + inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { + return static_cast( static_cast( lhs ) | static_cast( rhs ) ); + } + + inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } + inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } + inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } + +} // end namespace Catch + +// #included from: catch_assertionresult.h +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED + +#include + +namespace Catch { + + struct AssertionInfo + { + AssertionInfo() {} + AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ); + + std::string macroName; + SourceLineInfo lineInfo; + std::string capturedExpression; + ResultDisposition::Flags resultDisposition; + }; + + struct AssertionResultData + { + AssertionResultData() : resultType( ResultWas::Unknown ) {} + + std::string reconstructedExpression; + std::string message; + ResultWas::OfType resultType; + }; + + class AssertionResult { + public: + AssertionResult(); + AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); + ~AssertionResult(); +# ifdef CATCH_CPP11_OR_GREATER + AssertionResult( AssertionResult const& ) = default; + AssertionResult( AssertionResult && ) = default; + AssertionResult& operator = ( AssertionResult const& ) = default; + AssertionResult& operator = ( AssertionResult && ) = default; +# endif + + bool isOk() const; + bool succeeded() const; + ResultWas::OfType getResultType() const; + bool hasExpression() const; + bool hasMessage() const; + std::string getExpression() const; + std::string getExpressionInMacro() const; + bool hasExpandedExpression() const; + std::string getExpandedExpression() const; + std::string getMessage() const; + SourceLineInfo getSourceInfo() const; + std::string getTestMacroName() const; + + protected: + AssertionInfo m_info; + AssertionResultData m_resultData; + }; + +} // end namespace Catch + +namespace Catch { + + struct TestFailureException{}; + + template class ExpressionLhs; + + struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; + + struct CopyableStream { + CopyableStream() {} + CopyableStream( CopyableStream const& other ) { + oss << other.oss.str(); + } + CopyableStream& operator=( CopyableStream const& other ) { + oss.str(""); + oss << other.oss.str(); + return *this; + } + std::ostringstream oss; + }; + + class ResultBuilder { + public: + ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition ); + + template + ExpressionLhs operator->* ( T const& operand ); + ExpressionLhs operator->* ( bool value ); + + template + ResultBuilder& operator << ( T const& value ) { + m_stream.oss << value; + return *this; + } + + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + + ResultBuilder& setResultType( ResultWas::OfType result ); + ResultBuilder& setResultType( bool result ); + ResultBuilder& setLhs( std::string const& lhs ); + ResultBuilder& setRhs( std::string const& rhs ); + ResultBuilder& setOp( std::string const& op ); + + void endExpression(); + + std::string reconstructExpression() const; + AssertionResult build() const; + + void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); + void captureResult( ResultWas::OfType resultType ); + void captureExpression(); + void react(); + bool shouldDebugBreak() const; + bool allowThrows() const; + + private: + AssertionInfo m_assertionInfo; + AssertionResultData m_data; + struct ExprComponents { + ExprComponents() : testFalse( false ) {} + bool testFalse; + std::string lhs, rhs, op; + } m_exprComponents; + CopyableStream m_stream; + + bool m_shouldDebugBreak; + bool m_shouldThrow; + }; + +} // namespace Catch + +// Include after due to circular dependency: +// #included from: catch_expression_lhs.hpp +#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED + +// #included from: catch_evaluate.hpp +#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#endif + +#include + +namespace Catch { +namespace Internal { + + enum Operator { + IsEqualTo, + IsNotEqualTo, + IsLessThan, + IsGreaterThan, + IsLessThanOrEqualTo, + IsGreaterThanOrEqualTo + }; + + template struct OperatorTraits { static const char* getName(){ return "*error*"; } }; + template<> struct OperatorTraits { static const char* getName(){ return "=="; } }; + template<> struct OperatorTraits { static const char* getName(){ return "!="; } }; + template<> struct OperatorTraits { static const char* getName(){ return "<"; } }; + template<> struct OperatorTraits { static const char* getName(){ return ">"; } }; + template<> struct OperatorTraits { static const char* getName(){ return "<="; } }; + template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; + + template + inline T& opCast(T const& t) { return const_cast(t); } + +// nullptr_t support based on pull request #154 from Konstantin Baumann +#ifdef CATCH_CONFIG_CPP11_NULLPTR + inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } +#endif // CATCH_CONFIG_CPP11_NULLPTR + + // So the compare overloads can be operator agnostic we convey the operator as a template + // enum, which is used to specialise an Evaluator for doing the comparison. + template + class Evaluator{}; + + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs) { + return opCast( lhs ) == opCast( rhs ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) != opCast( rhs ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) < opCast( rhs ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) > opCast( rhs ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) >= opCast( rhs ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) <= opCast( rhs ); + } + }; + + template + bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { + return Evaluator::evaluate( lhs, rhs ); + } + + // This level of indirection allows us to specialise for integer types + // to avoid signed/ unsigned warnings + + // "base" overload + template + bool compare( T1 const& lhs, T2 const& rhs ) { + return Evaluator::evaluate( lhs, rhs ); + } + + // unsigned X to int + template bool compare( unsigned int lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned long lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned char lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + + // unsigned X to long + template bool compare( unsigned int lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned long lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned char lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + + // int to unsigned X + template bool compare( int lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( int lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( int lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // long to unsigned X + template bool compare( long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long (when comparing against NULL) + template bool compare( long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } + + // pointer to int (when comparing against NULL) + template bool compare( int lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, int rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } + +#ifdef CATCH_CONFIG_CPP11_NULLPTR + // pointer to nullptr_t (when comparing against nullptr) + template bool compare( std::nullptr_t, T* rhs ) { + return Evaluator::evaluate( NULL, rhs ); + } + template bool compare( T* lhs, std::nullptr_t ) { + return Evaluator::evaluate( lhs, NULL ); + } +#endif // CATCH_CONFIG_CPP11_NULLPTR + +} // end of namespace Internal +} // end of namespace Catch + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// #included from: catch_tostring.h +#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED + +// #included from: catch_sfinae.hpp +#define TWOBLUECUBES_CATCH_SFINAE_HPP_INCLUDED + +// Try to detect if the current compiler supports SFINAE + +namespace Catch { + + struct TrueType { + static const bool value = true; + typedef void Enable; + char sizer[1]; + }; + struct FalseType { + static const bool value = false; + typedef void Disable; + char sizer[2]; + }; + +#ifdef CATCH_CONFIG_SFINAE + + template struct NotABooleanExpression; + + template struct If : NotABooleanExpression {}; + template<> struct If : TrueType {}; + template<> struct If : FalseType {}; + + template struct SizedIf; + template<> struct SizedIf : TrueType {}; + template<> struct SizedIf : FalseType {}; + +#endif // CATCH_CONFIG_SFINAE + +} // end namespace Catch + +#include +#include +#include +#include +#include + +#ifdef __OBJC__ +// #included from: catch_objc_arc.hpp +#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED + +#import + +#ifdef __has_feature +#define CATCH_ARC_ENABLED __has_feature(objc_arc) +#else +#define CATCH_ARC_ENABLED 0 +#endif + +void arcSafeRelease( NSObject* obj ); +id performOptionalSelector( id obj, SEL sel ); + +#if !CATCH_ARC_ENABLED +inline void arcSafeRelease( NSObject* obj ) { + [obj release]; +} +inline id performOptionalSelector( id obj, SEL sel ) { + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; + return nil; +} +#define CATCH_UNSAFE_UNRETAINED +#define CATCH_ARC_STRONG +#else +inline void arcSafeRelease( NSObject* ){} +inline id performOptionalSelector( id obj, SEL sel ) { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +#endif + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + return nil; +} +#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained +#define CATCH_ARC_STRONG __strong +#endif + +#endif + +namespace Catch { +namespace Detail { + +// SFINAE is currently disabled by default for all compilers. +// If the non SFINAE version of IsStreamInsertable is ambiguous for you +// and your compiler supports SFINAE, try #defining CATCH_CONFIG_SFINAE +#ifdef CATCH_CONFIG_SFINAE + + template + class IsStreamInsertableHelper { + template struct TrueIfSizeable : TrueType {}; + + template + static TrueIfSizeable dummy(T2*); + static FalseType dummy(...); + + public: + typedef SizedIf type; + }; + + template + struct IsStreamInsertable : IsStreamInsertableHelper::type {}; + +#else + + struct BorgType { + template BorgType( T const& ); + }; + + TrueType& testStreamable( std::ostream& ); + FalseType testStreamable( FalseType ); + + FalseType operator<<( std::ostream const&, BorgType const& ); + + template + struct IsStreamInsertable { + static std::ostream &s; + static T const&t; + enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; + }; + +#endif + + template + struct StringMakerBase { + template + static std::string convert( T const& ) { return "{?}"; } + }; + + template<> + struct StringMakerBase { + template + static std::string convert( T const& _value ) { + std::ostringstream oss; + oss << _value; + return oss.str(); + } + }; + + std::string rawMemoryToString( const void *object, std::size_t size ); + + template + inline std::string rawMemoryToString( const T& object ) { + return rawMemoryToString( &object, sizeof(object) ); + } + +} // end namespace Detail + +template +std::string toString( T const& value ); + +template +struct StringMaker : + Detail::StringMakerBase::value> {}; + +template +struct StringMaker { + template + static std::string convert( U* p ) { + if( !p ) + return INTERNAL_CATCH_STRINGIFY( NULL ); + else + return Detail::rawMemoryToString( p ); + } +}; + +template +struct StringMaker { + static std::string convert( R C::* p ) { + if( !p ) + return INTERNAL_CATCH_STRINGIFY( NULL ); + else + return Detail::rawMemoryToString( p ); + } +}; + +namespace Detail { + template + std::string rangeToString( InputIterator first, InputIterator last ); +} + +template +struct StringMaker > { + static std::string convert( std::vector const& v ) { + return Detail::rangeToString( v.begin(), v.end() ); + } +}; + +namespace Detail { + template + std::string makeString( T const& value ) { + return StringMaker::convert( value ); + } +} // end namespace Detail + +/// \brief converts any type to a string +/// +/// The default template forwards on to ostringstream - except when an +/// ostringstream overload does not exist - in which case it attempts to detect +/// that and writes {?}. +/// Overload (not specialise) this template for custom typs that you don't want +/// to provide an ostream overload for. +template +std::string toString( T const& value ) { + return StringMaker::convert( value ); +} + +// Built in overloads + +std::string toString( std::string const& value ); +std::string toString( std::wstring const& value ); +std::string toString( const char* const value ); +std::string toString( char* const value ); +std::string toString( const wchar_t* const value ); +std::string toString( wchar_t* const value ); +std::string toString( int value ); +std::string toString( unsigned long value ); +std::string toString( unsigned int value ); +std::string toString( const double value ); +std::string toString( const float value ); +std::string toString( bool value ); +std::string toString( char value ); +std::string toString( signed char value ); +std::string toString( unsigned char value ); + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ); +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ); + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); + std::string toString( NSObject* const& nsObject ); +#endif + + namespace Detail { + template + std::string rangeToString( InputIterator first, InputIterator last ) { + std::ostringstream oss; + oss << "{ "; + if( first != last ) { + oss << toString( *first ); + for( ++first ; first != last ; ++first ) { + oss << ", " << toString( *first ); + } + } + oss << " }"; + return oss.str(); + } +} + +} // end namespace Catch + +namespace Catch { + +// Wraps the LHS of an expression and captures the operator and RHS (if any) - +// wrapping them all in a ResultBuilder object +template +class ExpressionLhs { + ExpressionLhs& operator = ( ExpressionLhs const& ); +# ifdef CATCH_CPP11_OR_GREATER + ExpressionLhs& operator = ( ExpressionLhs && ) = delete; +# endif + +public: + ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {} +# ifdef CATCH_CPP11_OR_GREATER + ExpressionLhs( ExpressionLhs const& ) = default; + ExpressionLhs( ExpressionLhs && ) = default; +# endif + + template + ResultBuilder& operator == ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator != ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator < ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator > ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator <= ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator >= ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + ResultBuilder& operator == ( bool rhs ) { + return captureExpression( rhs ); + } + + ResultBuilder& operator != ( bool rhs ) { + return captureExpression( rhs ); + } + + void endExpression() { + bool value = m_lhs ? true : false; + m_rb + .setLhs( Catch::toString( value ) ) + .setResultType( value ) + .endExpression(); + } + + // Only simple binary expressions are allowed on the LHS. + // If more complex compositions are required then place the sub expression in parentheses + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + +private: + template + ResultBuilder& captureExpression( RhsT const& rhs ) { + return m_rb + .setResultType( Internal::compare( m_lhs, rhs ) ) + .setLhs( Catch::toString( m_lhs ) ) + .setRhs( Catch::toString( rhs ) ) + .setOp( Internal::OperatorTraits::getName() ); + } + +private: + ResultBuilder& m_rb; + T m_lhs; +}; + +} // end namespace Catch + + +namespace Catch { + + template + inline ExpressionLhs ResultBuilder::operator->* ( T const& operand ) { + return ExpressionLhs( *this, operand ); + } + + inline ExpressionLhs ResultBuilder::operator->* ( bool value ) { + return ExpressionLhs( *this, value ); + } + +} // namespace Catch + +// #included from: catch_message.h +#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED + +#include + +namespace Catch { + + struct MessageInfo { + MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ); + + std::string macroName; + SourceLineInfo lineInfo; + ResultWas::OfType type; + std::string message; + unsigned int sequence; + + bool operator == ( MessageInfo const& other ) const { + return sequence == other.sequence; + } + bool operator < ( MessageInfo const& other ) const { + return sequence < other.sequence; + } + private: + static unsigned int globalCount; + }; + + struct MessageBuilder { + MessageBuilder( std::string const& macroName, + SourceLineInfo const& lineInfo, + ResultWas::OfType type ) + : m_info( macroName, lineInfo, type ) + {} + + template + MessageBuilder& operator << ( T const& value ) { + m_stream << value; + return *this; + } + + MessageInfo m_info; + std::ostringstream m_stream; + }; + + class ScopedMessage { + public: + ScopedMessage( MessageBuilder const& builder ); + ScopedMessage( ScopedMessage const& other ); + ~ScopedMessage(); + + MessageInfo m_info; + }; + +} // end namespace Catch + +// #included from: catch_interfaces_capture.h +#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED + +#include + +namespace Catch { + + class TestCase; + class AssertionResult; + struct AssertionInfo; + struct SectionInfo; + struct MessageInfo; + class ScopedMessageBuilder; + struct Counts; + + struct IResultCapture { + + virtual ~IResultCapture(); + + virtual void assertionEnded( AssertionResult const& result ) = 0; + virtual bool sectionStarted( SectionInfo const& sectionInfo, + Counts& assertions ) = 0; + virtual void sectionEnded( SectionInfo const& name, Counts const& assertions, double _durationInSeconds ) = 0; + virtual void pushScopedMessage( MessageInfo const& message ) = 0; + virtual void popScopedMessage( MessageInfo const& message ) = 0; + + virtual std::string getCurrentTestName() const = 0; + virtual const AssertionResult* getLastResult() const = 0; + }; + + IResultCapture& getResultCapture(); +} + +// #included from: catch_debugger.h +#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED + +// #included from: catch_platform.h +#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED + +#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_MAC +#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_IPHONE +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) +#define CATCH_PLATFORM_WINDOWS +#endif + +#include + +namespace Catch{ + + bool isDebuggerActive(); + void writeToDebugConsole( std::string const& text ); +} + +#ifdef CATCH_PLATFORM_MAC + + // The following code snippet based on: + // http://cocoawithlove.com/2008/03/break-into-debugger.html + #ifdef DEBUG + #if defined(__ppc64__) || defined(__ppc__) + #define CATCH_BREAK_INTO_DEBUGGER() \ + if( Catch::isDebuggerActive() ) { \ + __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ + : : : "memory","r0","r3","r4" ); \ + } + #else + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );} + #endif + #endif + +#elif defined(_MSC_VER) + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) void __stdcall DebugBreak(); + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); } +#endif + +#ifndef CATCH_BREAK_INTO_DEBUGGER +#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); +#endif + +// #included from: catch_interfaces_runner.h +#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED + +namespace Catch { + class TestCase; + + struct IRunner { + virtual ~IRunner(); + virtual bool aborting() const = 0; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// In the event of a failure works out if the debugger needs to be invoked +// and/or an exception thrown and takes appropriate action. +// This needs to be done as a macro so the debugger will stop in the user +// source code rather than in Catch library code +#define INTERNAL_CATCH_REACT( resultBuilder ) \ + if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ + resultBuilder.react(); + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + ( __catchResult->*expr ).endExpression(); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::isTrue( false && (expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( !Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( ... ) { \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( exceptionType ) { \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#else + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << log + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#endif + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_INFO( log, macroName ) \ + Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \ + try { \ + std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \ + __catchResult \ + .setLhs( Catch::toString( arg ) ) \ + .setRhs( matcherAsString == "{?}" ? #matcher : matcherAsString ) \ + .setOp( "matches" ) \ + .setResultType( ::Catch::Matchers::matcher.match( arg ) ); \ + __catchResult.captureExpression(); \ + } catch( ... ) { \ + __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +// #included from: internal/catch_section.h +#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED + +// #included from: catch_section_info.h +#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED + +namespace Catch { + + struct SectionInfo { + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description = std::string() ); + + std::string name; + std::string description; + SourceLineInfo lineInfo; + }; + +} // end namespace Catch + +// #included from: catch_totals.hpp +#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED + +#include + +namespace Catch { + + struct Counts { + Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} + + Counts operator - ( Counts const& other ) const { + Counts diff; + diff.passed = passed - other.passed; + diff.failed = failed - other.failed; + diff.failedButOk = failedButOk - other.failedButOk; + return diff; + } + Counts& operator += ( Counts const& other ) { + passed += other.passed; + failed += other.failed; + failedButOk += other.failedButOk; + return *this; + } + + std::size_t total() const { + return passed + failed + failedButOk; + } + bool allPassed() const { + return failed == 0 && failedButOk == 0; + } + + std::size_t passed; + std::size_t failed; + std::size_t failedButOk; + }; + + struct Totals { + + Totals operator - ( Totals const& other ) const { + Totals diff; + diff.assertions = assertions - other.assertions; + diff.testCases = testCases - other.testCases; + return diff; + } + + Totals delta( Totals const& prevTotals ) const { + Totals diff = *this - prevTotals; + if( diff.assertions.failed > 0 ) + ++diff.testCases.failed; + else if( diff.assertions.failedButOk > 0 ) + ++diff.testCases.failedButOk; + else + ++diff.testCases.passed; + return diff; + } + + Totals& operator += ( Totals const& other ) { + assertions += other.assertions; + testCases += other.testCases; + return *this; + } + + Counts assertions; + Counts testCases; + }; +} + +// #included from: catch_timer.h +#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED + +#ifdef CATCH_PLATFORM_WINDOWS +typedef unsigned long long uint64_t; +#else +#include +#endif + +namespace Catch { + + class Timer { + public: + Timer() : m_ticks( 0 ) {} + void start(); + unsigned int getElapsedNanoseconds() const; + unsigned int getElapsedMilliseconds() const; + double getElapsedSeconds() const; + + private: + uint64_t m_ticks; + }; + +} // namespace Catch + +#include + +namespace Catch { + + class Section { + public: + Section( SectionInfo const& info ); + ~Section(); + + // This indicates whether the section should be executed or not + operator bool() const; + + private: +#ifdef CATCH_CPP11_OR_GREATER + Section( Section const& ) = delete; + Section( Section && ) = delete; + Section& operator = ( Section const& ) = delete; + Section& operator = ( Section && ) = delete; +#else + Section( Section const& info ); + Section& operator = ( Section const& ); +#endif + SectionInfo m_info; + + std::string m_name; + Counts m_assertions; + bool m_sectionIncluded; + Timer m_timer; + }; + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_SECTION( ... ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) +#else + #define INTERNAL_CATCH_SECTION( name, desc ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) +#endif + +// #included from: internal/catch_generators.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + +template +struct IGenerator { + virtual ~IGenerator() {} + virtual T getValue( std::size_t index ) const = 0; + virtual std::size_t size () const = 0; +}; + +template +class BetweenGenerator : public IGenerator { +public: + BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} + + virtual T getValue( std::size_t index ) const { + return m_from+static_cast( index ); + } + + virtual std::size_t size() const { + return static_cast( 1+m_to-m_from ); + } + +private: + + T m_from; + T m_to; +}; + +template +class ValuesGenerator : public IGenerator { +public: + ValuesGenerator(){} + + void add( T value ) { + m_values.push_back( value ); + } + + virtual T getValue( std::size_t index ) const { + return m_values[index]; + } + + virtual std::size_t size() const { + return m_values.size(); + } + +private: + std::vector m_values; +}; + +template +class CompositeGenerator { +public: + CompositeGenerator() : m_totalSize( 0 ) {} + + // *** Move semantics, similar to auto_ptr *** + CompositeGenerator( CompositeGenerator& other ) + : m_fileInfo( other.m_fileInfo ), + m_totalSize( 0 ) + { + move( other ); + } + + CompositeGenerator& setFileInfo( const char* fileInfo ) { + m_fileInfo = fileInfo; + return *this; + } + + ~CompositeGenerator() { + deleteAll( m_composed ); + } + + operator T () const { + size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); + + typename std::vector*>::const_iterator it = m_composed.begin(); + typename std::vector*>::const_iterator itEnd = m_composed.end(); + for( size_t index = 0; it != itEnd; ++it ) + { + const IGenerator* generator = *it; + if( overallIndex >= index && overallIndex < index + generator->size() ) + { + return generator->getValue( overallIndex-index ); + } + index += generator->size(); + } + CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); + return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so + } + + void add( const IGenerator* generator ) { + m_totalSize += generator->size(); + m_composed.push_back( generator ); + } + + CompositeGenerator& then( CompositeGenerator& other ) { + move( other ); + return *this; + } + + CompositeGenerator& then( T value ) { + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( value ); + add( valuesGen ); + return *this; + } + +private: + + void move( CompositeGenerator& other ) { + std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) ); + m_totalSize += other.m_totalSize; + other.m_composed.clear(); + } + + std::vector*> m_composed; + std::string m_fileInfo; + size_t m_totalSize; +}; + +namespace Generators +{ + template + CompositeGenerator between( T from, T to ) { + CompositeGenerator generators; + generators.add( new BetweenGenerator( from, to ) ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2 ) { + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + generators.add( valuesGen ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2, T val3 ){ + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + generators.add( valuesGen ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2, T val3, T val4 ) { + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + valuesGen->add( val4 ); + generators.add( valuesGen ); + return generators; + } + +} // end namespace Generators + +using namespace Generators; + +} // end namespace Catch + +#define INTERNAL_CATCH_LINESTR2( line ) #line +#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) + +#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) + +// #included from: internal/catch_interfaces_exception.h +#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED + +#include +// #included from: catch_interfaces_registry_hub.h +#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED + +#include + +namespace Catch { + + class TestCase; + struct ITestCaseRegistry; + struct IExceptionTranslatorRegistry; + struct IExceptionTranslator; + struct IReporterRegistry; + struct IReporterFactory; + + struct IRegistryHub { + virtual ~IRegistryHub(); + + virtual IReporterRegistry const& getReporterRegistry() const = 0; + virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; + }; + + struct IMutableRegistryHub { + virtual ~IMutableRegistryHub(); + virtual void registerReporter( std::string const& name, IReporterFactory* factory ) = 0; + virtual void registerTest( TestCase const& testInfo ) = 0; + virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; + }; + + IRegistryHub& getRegistryHub(); + IMutableRegistryHub& getMutableRegistryHub(); + void cleanUp(); + std::string translateActiveException(); + +} + + +namespace Catch { + + typedef std::string(*exceptionTranslateFunction)(); + + struct IExceptionTranslator { + virtual ~IExceptionTranslator(); + virtual std::string translate() const = 0; + }; + + struct IExceptionTranslatorRegistry { + virtual ~IExceptionTranslatorRegistry(); + + virtual std::string translateActiveException() const = 0; + }; + + class ExceptionTranslatorRegistrar { + template + class ExceptionTranslator : public IExceptionTranslator { + public: + + ExceptionTranslator( std::string(*translateFunction)( T& ) ) + : m_translateFunction( translateFunction ) + {} + + virtual std::string translate() const { + try { + throw; + } + catch( T& ex ) { + return m_translateFunction( ex ); + } + } + + protected: + std::string(*m_translateFunction)( T& ); + }; + + public: + template + ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { + getMutableRegistryHub().registerTranslator + ( new ExceptionTranslator( translateFunction ) ); + } + }; +} + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \ + namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ) + +// #included from: internal/catch_approx.hpp +#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED + +#include +#include + +namespace Catch { +namespace Detail { + + class Approx { + public: + explicit Approx ( double value ) + : m_epsilon( std::numeric_limits::epsilon()*100 ), + m_scale( 1.0 ), + m_value( value ) + {} + + Approx( Approx const& other ) + : m_epsilon( other.m_epsilon ), + m_scale( other.m_scale ), + m_value( other.m_value ) + {} + + static Approx custom() { + return Approx( 0 ); + } + + Approx operator()( double value ) { + Approx approx( value ); + approx.epsilon( m_epsilon ); + approx.scale( m_scale ); + return approx; + } + + friend bool operator == ( double lhs, Approx const& rhs ) { + // Thanks to Richard Harris for his help refining this formula + return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) ); + } + + friend bool operator == ( Approx const& lhs, double rhs ) { + return operator==( rhs, lhs ); + } + + friend bool operator != ( double lhs, Approx const& rhs ) { + return !operator==( lhs, rhs ); + } + + friend bool operator != ( Approx const& lhs, double rhs ) { + return !operator==( rhs, lhs ); + } + + Approx& epsilon( double newEpsilon ) { + m_epsilon = newEpsilon; + return *this; + } + + Approx& scale( double newScale ) { + m_scale = newScale; + return *this; + } + + std::string toString() const { + std::ostringstream oss; + oss << "Approx( " << Catch::toString( m_value ) << " )"; + return oss.str(); + } + + private: + double m_epsilon; + double m_scale; + double m_value; + }; +} + +template<> +inline std::string toString( Detail::Approx const& value ) { + return value.toString(); +} + +} // end namespace Catch + +// #included from: internal/catch_matchers.hpp +#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED + +namespace Catch { +namespace Matchers { + namespace Impl { + + template + struct Matcher : SharedImpl + { + typedef ExpressionT ExpressionType; + + virtual ~Matcher() {} + virtual Ptr clone() const = 0; + virtual bool match( ExpressionT const& expr ) const = 0; + virtual std::string toString() const = 0; + }; + + template + struct MatcherImpl : Matcher { + + virtual Ptr > clone() const { + return Ptr >( new DerivedT( static_cast( *this ) ) ); + } + }; + + namespace Generic { + + template + class AllOf : public MatcherImpl, ExpressionT> { + public: + + AllOf() {} + AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} + + AllOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( !m_matchers[i]->match( expr ) ) + return false; + return true; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " and "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + private: + std::vector > > m_matchers; + }; + + template + class AnyOf : public MatcherImpl, ExpressionT> { + public: + + AnyOf() {} + AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} + + AnyOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( m_matchers[i]->match( expr ) ) + return true; + return false; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " or "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + private: + std::vector > > m_matchers; + }; + + } + + namespace StdString { + + inline std::string makeString( std::string const& str ) { return str; } + inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } + + struct Equals : MatcherImpl { + Equals( std::string const& str ) : m_str( str ){} + Equals( Equals const& other ) : m_str( other.m_str ){} + + virtual ~Equals(); + + virtual bool match( std::string const& expr ) const { + return m_str == expr; + } + virtual std::string toString() const { + return "equals: \"" + m_str + "\""; + } + + std::string m_str; + }; + + struct Contains : MatcherImpl { + Contains( std::string const& substr ) : m_substr( substr ){} + Contains( Contains const& other ) : m_substr( other.m_substr ){} + + virtual ~Contains(); + + virtual bool match( std::string const& expr ) const { + return expr.find( m_substr ) != std::string::npos; + } + virtual std::string toString() const { + return "contains: \"" + m_substr + "\""; + } + + std::string m_substr; + }; + + struct StartsWith : MatcherImpl { + StartsWith( std::string const& substr ) : m_substr( substr ){} + StartsWith( StartsWith const& other ) : m_substr( other.m_substr ){} + + virtual ~StartsWith(); + + virtual bool match( std::string const& expr ) const { + return expr.find( m_substr ) == 0; + } + virtual std::string toString() const { + return "starts with: \"" + m_substr + "\""; + } + + std::string m_substr; + }; + + struct EndsWith : MatcherImpl { + EndsWith( std::string const& substr ) : m_substr( substr ){} + EndsWith( EndsWith const& other ) : m_substr( other.m_substr ){} + + virtual ~EndsWith(); + + virtual bool match( std::string const& expr ) const { + return expr.find( m_substr ) == expr.size() - m_substr.size(); + } + virtual std::string toString() const { + return "ends with: \"" + m_substr + "\""; + } + + std::string m_substr; + }; + } // namespace StdString + } // namespace Impl + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); + } + + inline Impl::StdString::Equals Equals( std::string const& str ) { + return Impl::StdString::Equals( str ); + } + inline Impl::StdString::Equals Equals( const char* str ) { + return Impl::StdString::Equals( Impl::StdString::makeString( str ) ); + } + inline Impl::StdString::Contains Contains( std::string const& substr ) { + return Impl::StdString::Contains( substr ); + } + inline Impl::StdString::Contains Contains( const char* substr ) { + return Impl::StdString::Contains( Impl::StdString::makeString( substr ) ); + } + inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { + return Impl::StdString::StartsWith( substr ); + } + inline Impl::StdString::StartsWith StartsWith( const char* substr ) { + return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); + } + inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { + return Impl::StdString::EndsWith( substr ); + } + inline Impl::StdString::EndsWith EndsWith( const char* substr ) { + return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); + } + +} // namespace Matchers + +using namespace Matchers; + +} // namespace Catch + +// #included from: internal/catch_interfaces_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED + +// #included from: catch_tag_alias.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED + +#include + +namespace Catch { + + struct TagAlias { + TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} + + std::string tag; + SourceLineInfo lineInfo; + }; + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } +// #included from: catch_option.hpp +#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED + +namespace Catch { + + // An optional type + template + class Option { + public: + Option() : nullableValue( NULL ) {} + Option( T const& _value ) + : nullableValue( new( storage ) T( _value ) ) + {} + Option( Option const& _other ) + : nullableValue( _other ? new( storage ) T( *_other ) : NULL ) + {} + + ~Option() { + reset(); + } + + Option& operator= ( Option const& _other ) { + if( &_other != this ) { + reset(); + if( _other ) + nullableValue = new( storage ) T( *_other ); + } + return *this; + } + Option& operator = ( T const& _value ) { + reset(); + nullableValue = new( storage ) T( _value ); + return *this; + } + + void reset() { + if( nullableValue ) + nullableValue->~T(); + nullableValue = NULL; + } + + T& operator*() { return *nullableValue; } + T const& operator*() const { return *nullableValue; } + T* operator->() { return nullableValue; } + const T* operator->() const { return nullableValue; } + + T valueOr( T const& defaultValue ) const { + return nullableValue ? *nullableValue : defaultValue; + } + + bool some() const { return nullableValue != NULL; } + bool none() const { return nullableValue == NULL; } + + bool operator !() const { return nullableValue == NULL; } + operator SafeBool::type() const { + return SafeBool::makeSafe( some() ); + } + + private: + T* nullableValue; + char storage[sizeof(T)]; + }; + +} // end namespace Catch + +namespace Catch { + + struct ITagAliasRegistry { + virtual ~ITagAliasRegistry(); + virtual Option find( std::string const& alias ) const = 0; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; + + static ITagAliasRegistry const& get(); + }; + +} // end namespace Catch + +// These files are included here so the single_include script doesn't put them +// in the conditionally compiled sections +// #included from: internal/catch_test_case_info.h +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED + +#include +#include + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + struct ITestCase; + + struct TestCaseInfo { + enum SpecialProperties{ + None = 0, + IsHidden = 1 << 1, + ShouldFail = 1 << 2, + MayFail = 1 << 3, + Throws = 1 << 4 + }; + + TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set const& _tags, + SourceLineInfo const& _lineInfo ); + + TestCaseInfo( TestCaseInfo const& other ); + + bool isHidden() const; + bool throws() const; + bool okToFail() const; + bool expectedToFail() const; + + std::string name; + std::string className; + std::string description; + std::set tags; + std::set lcaseTags; + std::string tagsAsString; + SourceLineInfo lineInfo; + SpecialProperties properties; + }; + + class TestCase : public TestCaseInfo { + public: + + TestCase( ITestCase* testCase, TestCaseInfo const& info ); + TestCase( TestCase const& other ); + + TestCase withName( std::string const& _newName ) const; + + void invoke() const; + + TestCaseInfo const& getTestCaseInfo() const; + + void swap( TestCase& other ); + bool operator == ( TestCase const& other ) const; + bool operator < ( TestCase const& other ) const; + TestCase& operator = ( TestCase const& other ); + + private: + Ptr test; + }; + + TestCase makeTestCase( ITestCase* testCase, + std::string const& className, + std::string const& name, + std::string const& description, + SourceLineInfo const& lineInfo ); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + + +#ifdef __OBJC__ +// #included from: internal/catch_objc.hpp +#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED + +#import + +#include + +// NB. Any general catch headers included here must be included +// in catch.hpp first to make sure they are included by the single +// header for non obj-usage + +/////////////////////////////////////////////////////////////////////////////// +// This protocol is really only here for (self) documenting purposes, since +// all its methods are optional. +@protocol OcFixture + +@optional + +-(void) setUp; +-(void) tearDown; + +@end + +namespace Catch { + + class OcMethod : public SharedImpl { + + public: + OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} + + virtual void invoke() const { + id obj = [[m_cls alloc] init]; + + performOptionalSelector( obj, @selector(setUp) ); + performOptionalSelector( obj, m_sel ); + performOptionalSelector( obj, @selector(tearDown) ); + + arcSafeRelease( obj ); + } + private: + virtual ~OcMethod() {} + + Class m_cls; + SEL m_sel; + }; + + namespace Detail{ + + inline std::string getAnnotation( Class cls, + std::string const& annotationName, + std::string const& testCaseName ) { + NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; + SEL sel = NSSelectorFromString( selStr ); + arcSafeRelease( selStr ); + id value = performOptionalSelector( cls, sel ); + if( value ) + return [(NSString*)value UTF8String]; + return ""; + } + } + + inline size_t registerTestMethods() { + size_t noTestMethods = 0; + int noClasses = objc_getClassList( NULL, 0 ); + + Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); + objc_getClassList( classes, noClasses ); + + for( int c = 0; c < noClasses; c++ ) { + Class cls = classes[c]; + { + u_int count; + Method* methods = class_copyMethodList( cls, &count ); + for( u_int m = 0; m < count ; m++ ) { + SEL selector = method_getName(methods[m]); + std::string methodName = sel_getName(selector); + if( startsWith( methodName, "Catch_TestCase_" ) ) { + std::string testCaseName = methodName.substr( 15 ); + std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); + std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); + const char* className = class_getName( cls ); + + getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); + noTestMethods++; + } + } + free(methods); + } + } + return noTestMethods; + } + + namespace Matchers { + namespace Impl { + namespace NSStringMatchers { + + template + struct StringHolder : MatcherImpl{ + StringHolder( NSString* substr ) : m_substr( [substr copy] ){} + StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} + StringHolder() { + arcSafeRelease( m_substr ); + } + + NSString* m_substr; + }; + + struct Equals : StringHolder { + Equals( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str isEqualToString:m_substr]; + } + + virtual std::string toString() const { + return "equals string: " + Catch::toString( m_substr ); + } + }; + + struct Contains : StringHolder { + Contains( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location != NSNotFound; + } + + virtual std::string toString() const { + return "contains string: " + Catch::toString( m_substr ); + } + }; + + struct StartsWith : StringHolder { + StartsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == 0; + } + + virtual std::string toString() const { + return "starts with: " + Catch::toString( m_substr ); + } + }; + struct EndsWith : StringHolder { + EndsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == [str length] - [m_substr length]; + } + + virtual std::string toString() const { + return "ends with: " + Catch::toString( m_substr ); + } + }; + + } // namespace NSStringMatchers + } // namespace Impl + + inline Impl::NSStringMatchers::Equals + Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } + + inline Impl::NSStringMatchers::Contains + Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } + + inline Impl::NSStringMatchers::StartsWith + StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } + + inline Impl::NSStringMatchers::EndsWith + EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } + + } // namespace Matchers + + using namespace Matchers; + +} // namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define OC_TEST_CASE( name, desc )\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ +{\ +return @ name; \ +}\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ +{ \ +return @ desc; \ +} \ +-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) + +#endif + +#ifdef CATCH_CONFIG_RUNNER +// #included from: internal/catch_impl.hpp +#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED + +// Collect all the implementation files together here +// These are the equivalent of what would usually be cpp files + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +// #included from: catch_runner.hpp +#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED + +// #included from: internal/catch_commandline.hpp +#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED + +// #included from: catch_config.hpp +#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED + +// #included from: catch_test_spec_parser.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// #included from: catch_test_spec.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +#include +#include + +namespace Catch { + + class TestSpec { + struct Pattern : SharedImpl<> { + virtual ~Pattern(); + virtual bool matches( TestCaseInfo const& testCase ) const = 0; + }; + class NamePattern : public Pattern { + enum WildcardPosition { + NoWildcard = 0, + WildcardAtStart = 1, + WildcardAtEnd = 2, + WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd + }; + + public: + NamePattern( std::string const& name ) : m_name( toLower( name ) ), m_wildcard( NoWildcard ) { + if( startsWith( m_name, "*" ) ) { + m_name = m_name.substr( 1 ); + m_wildcard = WildcardAtStart; + } + if( endsWith( m_name, "*" ) ) { + m_name = m_name.substr( 0, m_name.size()-1 ); + m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); + } + } + virtual ~NamePattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_name == toLower( testCase.name ); + case WildcardAtStart: + return endsWith( toLower( testCase.name ), m_name ); + case WildcardAtEnd: + return startsWith( toLower( testCase.name ), m_name ); + case WildcardAtBothEnds: + return contains( toLower( testCase.name ), m_name ); + } + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + throw std::logic_error( "Unknown enum" ); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + } + private: + std::string m_name; + WildcardPosition m_wildcard; + }; + class TagPattern : public Pattern { + public: + TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} + virtual ~TagPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); + } + private: + std::string m_tag; + }; + class ExcludedPattern : public Pattern { + public: + ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} + virtual ~ExcludedPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } + private: + Ptr m_underlyingPattern; + }; + + struct Filter { + std::vector > m_patterns; + + bool matches( TestCaseInfo const& testCase ) const { + // All patterns in a filter must match for the filter to be a match + for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) + if( !(*it)->matches( testCase ) ) + return false; + return true; + } + }; + + public: + bool hasFilters() const { + return !m_filters.empty(); + } + bool matches( TestCaseInfo const& testCase ) const { + // A TestSpec matches if any filter matches + for( std::vector::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) + if( it->matches( testCase ) ) + return true; + return false; + } + + private: + std::vector m_filters; + + friend class TestSpecParser; + }; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +namespace Catch { + + class TestSpecParser { + enum Mode{ None, Name, QuotedName, Tag }; + Mode m_mode; + bool m_exclusion; + std::size_t m_start, m_pos; + std::string m_arg; + TestSpec::Filter m_currentFilter; + TestSpec m_testSpec; + ITagAliasRegistry const* m_tagAliases; + + public: + TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} + + TestSpecParser& parse( std::string const& arg ) { + m_mode = None; + m_exclusion = false; + m_start = std::string::npos; + m_arg = m_tagAliases->expandAliases( arg ); + for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) + visitChar( m_arg[m_pos] ); + if( m_mode == Name ) + addPattern(); + return *this; + } + TestSpec testSpec() { + addFilter(); + return m_testSpec; + } + private: + void visitChar( char c ) { + if( m_mode == None ) { + switch( c ) { + case ' ': return; + case '~': m_exclusion = true; return; + case '[': return startNewMode( Tag, ++m_pos ); + case '"': return startNewMode( QuotedName, ++m_pos ); + default: startNewMode( Name, m_pos ); break; + } + } + if( m_mode == Name ) { + if( c == ',' ) { + addPattern(); + addFilter(); + } + else if( c == '[' ) { + if( subString() == "exclude:" ) + m_exclusion = true; + else + addPattern(); + startNewMode( Tag, ++m_pos ); + } + } + else if( m_mode == QuotedName && c == '"' ) + addPattern(); + else if( m_mode == Tag && c == ']' ) + addPattern(); + } + void startNewMode( Mode mode, std::size_t start ) { + m_mode = mode; + m_start = start; + } + std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } + template + void addPattern() { + std::string token = subString(); + if( startsWith( token, "exclude:" ) ) { + m_exclusion = true; + token = token.substr( 8 ); + } + if( !token.empty() ) { + Ptr pattern = new T( token ); + if( m_exclusion ) + pattern = new TestSpec::ExcludedPattern( pattern ); + m_currentFilter.m_patterns.push_back( pattern ); + } + m_exclusion = false; + m_mode = None; + } + void addFilter() { + if( !m_currentFilter.m_patterns.empty() ) { + m_testSpec.m_filters.push_back( m_currentFilter ); + m_currentFilter = TestSpec::Filter(); + } + } + }; + inline TestSpec parseTestSpec( std::string const& arg ) { + return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// #included from: catch_interfaces_config.h +#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED + +#include +#include +#include + +namespace Catch { + + struct Verbosity { enum Level { + NoOutput = 0, + Quiet, + Normal + }; }; + + struct WarnAbout { enum What { + Nothing = 0x00, + NoAssertions = 0x01 + }; }; + + struct ShowDurations { enum OrNot { + DefaultForReporter, + Always, + Never + }; }; + + class TestSpec; + + struct IConfig : IShared { + + virtual ~IConfig(); + + virtual bool allowThrows() const = 0; + virtual std::ostream& stream() const = 0; + virtual std::string name() const = 0; + virtual bool includeSuccessfulResults() const = 0; + virtual bool shouldDebugBreak() const = 0; + virtual bool warnAboutMissingAssertions() const = 0; + virtual int abortAfter() const = 0; + virtual bool showInvisibles() const = 0; + virtual ShowDurations::OrNot showDurations() const = 0; + virtual TestSpec const& testSpec() const = 0; + }; +} + +// #included from: catch_stream.h +#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED + +#include + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + class Stream { + public: + Stream(); + Stream( std::streambuf* _streamBuf, bool _isOwned ); + void release(); + + std::streambuf* streamBuf; + + private: + bool isOwned; + }; +} + +#include +#include +#include +#include + +#ifndef CATCH_CONFIG_CONSOLE_WIDTH +#define CATCH_CONFIG_CONSOLE_WIDTH 80 +#endif + +namespace Catch { + + struct ConfigData { + + ConfigData() + : listTests( false ), + listTags( false ), + listReporters( false ), + listTestNamesOnly( false ), + showSuccessfulTests( false ), + shouldDebugBreak( false ), + noThrow( false ), + showHelp( false ), + showInvisibles( false ), + abortAfter( -1 ), + verbosity( Verbosity::Normal ), + warnings( WarnAbout::Nothing ), + showDurations( ShowDurations::DefaultForReporter ) + {} + + bool listTests; + bool listTags; + bool listReporters; + bool listTestNamesOnly; + + bool showSuccessfulTests; + bool shouldDebugBreak; + bool noThrow; + bool showHelp; + bool showInvisibles; + + int abortAfter; + + Verbosity::Level verbosity; + WarnAbout::What warnings; + ShowDurations::OrNot showDurations; + + std::string reporterName; + std::string outputFilename; + std::string name; + std::string processName; + + std::vector testsOrTags; + }; + + class Config : public SharedImpl { + private: + Config( Config const& other ); + Config& operator = ( Config const& other ); + virtual void dummy(); + public: + + Config() + : m_os( std::cout.rdbuf() ) + {} + + Config( ConfigData const& data ) + : m_data( data ), + m_os( std::cout.rdbuf() ) + { + if( !data.testsOrTags.empty() ) { + TestSpecParser parser( ITagAliasRegistry::get() ); + for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) + parser.parse( data.testsOrTags[i] ); + m_testSpec = parser.testSpec(); + } + } + + virtual ~Config() { + m_os.rdbuf( std::cout.rdbuf() ); + m_stream.release(); + } + + void setFilename( std::string const& filename ) { + m_data.outputFilename = filename; + } + + std::string const& getFilename() const { + return m_data.outputFilename ; + } + + bool listTests() const { return m_data.listTests; } + bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } + bool listTags() const { return m_data.listTags; } + bool listReporters() const { return m_data.listReporters; } + + std::string getProcessName() const { return m_data.processName; } + + bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } + + void setStreamBuf( std::streambuf* buf ) { + m_os.rdbuf( buf ? buf : std::cout.rdbuf() ); + } + + void useStream( std::string const& streamName ) { + Stream stream = createStream( streamName ); + setStreamBuf( stream.streamBuf ); + m_stream.release(); + m_stream = stream; + } + + std::string getReporterName() const { return m_data.reporterName; } + + int abortAfter() const { return m_data.abortAfter; } + + TestSpec const& testSpec() const { return m_testSpec; } + + bool showHelp() const { return m_data.showHelp; } + bool showInvisibles() const { return m_data.showInvisibles; } + + // IConfig interface + virtual bool allowThrows() const { return !m_data.noThrow; } + virtual std::ostream& stream() const { return m_os; } + virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } + virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } + virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } + virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; } + + private: + ConfigData m_data; + + Stream m_stream; + mutable std::ostream m_os; + TestSpec m_testSpec; + }; + +} // end namespace Catch + +// #included from: catch_clara.h +#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED + +// Use Catch's value for console width (store Clara's off to the side, if present) +#ifdef CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH +#undef CLARA_CONFIG_CONSOLE_WIDTH +#endif +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +// Declare Clara inside the Catch namespace +#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { +// #included from: ../external/clara.h + +// Only use header guard if we are not using an outer namespace +#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) + +#ifndef STITCH_CLARA_OPEN_NAMESPACE +#define TWOBLUECUBES_CLARA_H_INCLUDED +#define STITCH_CLARA_OPEN_NAMESPACE +#define STITCH_CLARA_CLOSE_NAMESPACE +#else +#define STITCH_CLARA_CLOSE_NAMESPACE } +#endif + +#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE + +// ----------- #included from tbc_text_format.h ----------- + +// Only use header guard if we are not using an outer namespace +#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) +#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +#define TBC_TEXT_FORMAT_H_INCLUDED +#endif + +#include +#include +#include + +// Use optional outer namespace +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TBC_TEXT_FORMAT_H_INCLUDED + +// ----------- end of #include from tbc_text_format.h ----------- +// ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h + +#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE + +#include +#include +#include +#include + +// Use optional outer namespace +#ifdef STITCH_CLARA_OPEN_NAMESPACE +STITCH_CLARA_OPEN_NAMESPACE +#endif + +namespace Clara { + + struct UnpositionalTag {}; + + extern UnpositionalTag _; + +#ifdef CLARA_CONFIG_MAIN + UnpositionalTag _; +#endif + + namespace Detail { + +#ifdef CLARA_CONSOLE_WIDTH + const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + using namespace Tbc; + + inline bool startsWith( std::string const& str, std::string const& prefix ) { + return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; + } + + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + + template struct IsBool { static const bool value = false; }; + template<> struct IsBool { static const bool value = true; }; + + template + void convertInto( std::string const& _source, T& _dest ) { + std::stringstream ss; + ss << _source; + ss >> _dest; + if( ss.fail() ) + throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); + } + inline void convertInto( std::string const& _source, std::string& _dest ) { + _dest = _source; + } + inline void convertInto( std::string const& _source, bool& _dest ) { + std::string sourceLC = _source; + std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower ); + if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) + _dest = true; + else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) + _dest = false; + else + throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); + } + inline void convertInto( bool _source, bool& _dest ) { + _dest = _source; + } + template + inline void convertInto( bool, T& ) { + throw std::runtime_error( "Invalid conversion" ); + } + + template + struct IArgFunction { + virtual ~IArgFunction() {} +# ifdef CATCH_CPP11_OR_GREATER + IArgFunction() = default; + IArgFunction( IArgFunction const& ) = default; +# endif + virtual void set( ConfigT& config, std::string const& value ) const = 0; + virtual void setFlag( ConfigT& config ) const = 0; + virtual bool takesArg() const = 0; + virtual IArgFunction* clone() const = 0; + }; + + template + class BoundArgFunction { + public: + BoundArgFunction() : functionObj( NULL ) {} + BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} + BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : NULL ) {} + BoundArgFunction& operator = ( BoundArgFunction const& other ) { + IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : NULL; + delete functionObj; + functionObj = newFunctionObj; + return *this; + } + ~BoundArgFunction() { delete functionObj; } + + void set( ConfigT& config, std::string const& value ) const { + functionObj->set( config, value ); + } + void setFlag( ConfigT& config ) const { + functionObj->setFlag( config ); + } + bool takesArg() const { return functionObj->takesArg(); } + + bool isSet() const { + return functionObj != NULL; + } + private: + IArgFunction* functionObj; + }; + + template + struct NullBinder : IArgFunction{ + virtual void set( C&, std::string const& ) const {} + virtual void setFlag( C& ) const {} + virtual bool takesArg() const { return true; } + virtual IArgFunction* clone() const { return new NullBinder( *this ); } + }; + + template + struct BoundDataMember : IArgFunction{ + BoundDataMember( M C::* _member ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + convertInto( stringValue, p.*member ); + } + virtual void setFlag( C& p ) const { + convertInto( true, p.*member ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundDataMember( *this ); } + M C::* member; + }; + template + struct BoundUnaryMethod : IArgFunction{ + BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + (p.*member)( value ); + } + virtual void setFlag( C& p ) const { + typename RemoveConstRef::type value; + convertInto( true, value ); + (p.*member)( value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundUnaryMethod( *this ); } + void (C::*member)( M ); + }; + template + struct BoundNullaryMethod : IArgFunction{ + BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + (p.*member)(); + } + virtual void setFlag( C& p ) const { + (p.*member)(); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundNullaryMethod( *this ); } + void (C::*member)(); + }; + + template + struct BoundUnaryFunction : IArgFunction{ + BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + function( obj ); + } + virtual void setFlag( C& p ) const { + function( p ); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundUnaryFunction( *this ); } + void (*function)( C& ); + }; + + template + struct BoundBinaryFunction : IArgFunction{ + BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + function( obj, value ); + } + virtual void setFlag( C& obj ) const { + typename RemoveConstRef::type value; + convertInto( true, value ); + function( obj, value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundBinaryFunction( *this ); } + void (*function)( C&, T ); + }; + + } // namespace Detail + + struct Parser { + Parser() : separators( " \t=:" ) {} + + struct Token { + enum Type { Positional, ShortOpt, LongOpt }; + Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} + Type type; + std::string data; + }; + + void parseIntoTokens( int argc, char const * const * argv, std::vector& tokens ) const { + const std::string doubleDash = "--"; + for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) + parseIntoTokens( argv[i] , tokens); + } + void parseIntoTokens( std::string arg, std::vector& tokens ) const { + while( !arg.empty() ) { + Parser::Token token( Parser::Token::Positional, arg ); + arg = ""; + if( token.data[0] == '-' ) { + if( token.data.size() > 1 && token.data[1] == '-' ) { + token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); + } + else { + token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) ); + if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) { + arg = "-" + token.data.substr( 1 ); + token.data = token.data.substr( 0, 1 ); + } + } + } + if( token.type != Parser::Token::Positional ) { + std::size_t pos = token.data.find_first_of( separators ); + if( pos != std::string::npos ) { + arg = token.data.substr( pos+1 ); + token.data = token.data.substr( 0, pos ); + } + } + tokens.push_back( token ); + } + } + std::string separators; + }; + + template + struct CommonArgProperties { + CommonArgProperties() {} + CommonArgProperties( Detail::BoundArgFunction const& _boundField ) : boundField( _boundField ) {} + + Detail::BoundArgFunction boundField; + std::string description; + std::string detail; + std::string placeholder; // Only value if boundField takes an arg + + bool takesArg() const { + return !placeholder.empty(); + } + void validate() const { + if( !boundField.isSet() ) + throw std::logic_error( "option not bound" ); + } + }; + struct OptionArgProperties { + std::vector shortNames; + std::string longName; + + bool hasShortName( std::string const& shortName ) const { + return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); + } + bool hasLongName( std::string const& _longName ) const { + return _longName == longName; + } + }; + struct PositionalArgProperties { + PositionalArgProperties() : position( -1 ) {} + int position; // -1 means non-positional (floating) + + bool isFixedPositional() const { + return position != -1; + } + }; + + template + class CommandLine { + + struct Arg : CommonArgProperties, OptionArgProperties, PositionalArgProperties { + Arg() {} + Arg( Detail::BoundArgFunction const& _boundField ) : CommonArgProperties( _boundField ) {} + + using CommonArgProperties::placeholder; // !TBD + + std::string dbgName() const { + if( !longName.empty() ) + return "--" + longName; + if( !shortNames.empty() ) + return "-" + shortNames[0]; + return "positional args"; + } + std::string commands() const { + std::ostringstream oss; + bool first = true; + std::vector::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); + for(; it != itEnd; ++it ) { + if( first ) + first = false; + else + oss << ", "; + oss << "-" << *it; + } + if( !longName.empty() ) { + if( !first ) + oss << ", "; + oss << "--" << longName; + } + if( !placeholder.empty() ) + oss << " <" << placeholder << ">"; + return oss.str(); + } + }; + + // NOTE: std::auto_ptr is deprecated in c++11/c++0x +#if defined(__cplusplus) && __cplusplus > 199711L + typedef std::unique_ptr ArgAutoPtr; +#else + typedef std::auto_ptr ArgAutoPtr; +#endif + + friend void addOptName( Arg& arg, std::string const& optName ) + { + if( optName.empty() ) + return; + if( Detail::startsWith( optName, "--" ) ) { + if( !arg.longName.empty() ) + throw std::logic_error( "Only one long opt may be specified. '" + + arg.longName + + "' already specified, now attempting to add '" + + optName + "'" ); + arg.longName = optName.substr( 2 ); + } + else if( Detail::startsWith( optName, "-" ) ) + arg.shortNames.push_back( optName.substr( 1 ) ); + else + throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); + } + friend void setPositionalArg( Arg& arg, int position ) + { + arg.position = position; + } + + class ArgBuilder { + public: + ArgBuilder( Arg* arg ) : m_arg( arg ) {} + + // Bind a non-boolean data member (requires placeholder string) + template + void bind( M C::* field, std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundDataMember( field ); + m_arg->placeholder = placeholder; + } + // Bind a boolean data member (no placeholder required) + template + void bind( bool C::* field ) { + m_arg->boundField = new Detail::BoundDataMember( field ); + } + + // Bind a method taking a single, non-boolean argument (requires a placeholder string) + template + void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); + m_arg->placeholder = placeholder; + } + + // Bind a method taking a single, boolean argument (no placeholder string required) + template + void bind( void (C::* unaryMethod)( bool ) ) { + m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); + } + + // Bind a method that takes no arguments (will be called if opt is present) + template + void bind( void (C::* nullaryMethod)() ) { + m_arg->boundField = new Detail::BoundNullaryMethod( nullaryMethod ); + } + + // Bind a free function taking a single argument - the object to operate on (no placeholder string required) + template + void bind( void (* unaryFunction)( C& ) ) { + m_arg->boundField = new Detail::BoundUnaryFunction( unaryFunction ); + } + + // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) + template + void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundBinaryFunction( binaryFunction ); + m_arg->placeholder = placeholder; + } + + ArgBuilder& describe( std::string const& description ) { + m_arg->description = description; + return *this; + } + ArgBuilder& detail( std::string const& detail ) { + m_arg->detail = detail; + return *this; + } + + protected: + Arg* m_arg; + }; + + class OptBuilder : public ArgBuilder { + public: + OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} + OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} + + OptBuilder& operator[]( std::string const& optName ) { + addOptName( *ArgBuilder::m_arg, optName ); + return *this; + } + }; + + public: + + CommandLine() + : m_boundProcessName( new Detail::NullBinder() ), + m_highestSpecifiedArgPosition( 0 ), + m_throwOnUnrecognisedTokens( false ) + {} + CommandLine( CommandLine const& other ) + : m_boundProcessName( other.m_boundProcessName ), + m_options ( other.m_options ), + m_positionalArgs( other.m_positionalArgs ), + m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), + m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) + { + if( other.m_floatingArg.get() ) + m_floatingArg = ArgAutoPtr( new Arg( *other.m_floatingArg ) ); + } + + CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { + m_throwOnUnrecognisedTokens = shouldThrow; + return *this; + } + + OptBuilder operator[]( std::string const& optName ) { + m_options.push_back( Arg() ); + addOptName( m_options.back(), optName ); + OptBuilder builder( &m_options.back() ); + return builder; + } + + ArgBuilder operator[]( int position ) { + m_positionalArgs.insert( std::make_pair( position, Arg() ) ); + if( position > m_highestSpecifiedArgPosition ) + m_highestSpecifiedArgPosition = position; + setPositionalArg( m_positionalArgs[position], position ); + ArgBuilder builder( &m_positionalArgs[position] ); + return builder; + } + + // Invoke this with the _ instance + ArgBuilder operator[]( UnpositionalTag ) { + if( m_floatingArg.get() ) + throw std::logic_error( "Only one unpositional argument can be added" ); + m_floatingArg = ArgAutoPtr( new Arg() ); + ArgBuilder builder( m_floatingArg.get() ); + return builder; + } + + template + void bindProcessName( M C::* field ) { + m_boundProcessName = new Detail::BoundDataMember( field ); + } + template + void bindProcessName( void (C::*_unaryMethod)( M ) ) { + m_boundProcessName = new Detail::BoundUnaryMethod( _unaryMethod ); + } + + void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { + typename std::vector::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; + std::size_t maxWidth = 0; + for( it = itBegin; it != itEnd; ++it ) + maxWidth = (std::max)( maxWidth, it->commands().size() ); + + for( it = itBegin; it != itEnd; ++it ) { + Detail::Text usage( it->commands(), Detail::TextAttributes() + .setWidth( maxWidth+indent ) + .setIndent( indent ) ); + Detail::Text desc( it->description, Detail::TextAttributes() + .setWidth( width - maxWidth - 3 ) ); + + for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { + std::string usageCol = i < usage.size() ? usage[i] : ""; + os << usageCol; + + if( i < desc.size() && !desc[i].empty() ) + os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) + << desc[i]; + os << "\n"; + } + } + } + std::string optUsage() const { + std::ostringstream oss; + optUsage( oss ); + return oss.str(); + } + + void argSynopsis( std::ostream& os ) const { + for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { + if( i > 1 ) + os << " "; + typename std::map::const_iterator it = m_positionalArgs.find( i ); + if( it != m_positionalArgs.end() ) + os << "<" << it->second.placeholder << ">"; + else if( m_floatingArg.get() ) + os << "<" << m_floatingArg->placeholder << ">"; + else + throw std::logic_error( "non consecutive positional arguments with no floating args" ); + } + // !TBD No indication of mandatory args + if( m_floatingArg.get() ) { + if( m_highestSpecifiedArgPosition > 1 ) + os << " "; + os << "[<" << m_floatingArg->placeholder << "> ...]"; + } + } + std::string argSynopsis() const { + std::ostringstream oss; + argSynopsis( oss ); + return oss.str(); + } + + void usage( std::ostream& os, std::string const& procName ) const { + validate(); + os << "usage:\n " << procName << " "; + argSynopsis( os ); + if( !m_options.empty() ) { + os << " [options]\n\nwhere options are: \n"; + optUsage( os, 2 ); + } + os << "\n"; + } + std::string usage( std::string const& procName ) const { + std::ostringstream oss; + usage( oss, procName ); + return oss.str(); + } + + ConfigT parse( int argc, char const * const * argv ) const { + ConfigT config; + parseInto( argc, argv, config ); + return config; + } + + std::vector parseInto( int argc, char const * const * argv, ConfigT& config ) const { + std::string processName = argv[0]; + std::size_t lastSlash = processName.find_last_of( "/\\" ); + if( lastSlash != std::string::npos ) + processName = processName.substr( lastSlash+1 ); + m_boundProcessName.set( config, processName ); + std::vector tokens; + Parser parser; + parser.parseIntoTokens( argc, argv, tokens ); + return populate( tokens, config ); + } + + std::vector populate( std::vector const& tokens, ConfigT& config ) const { + validate(); + std::vector unusedTokens = populateOptions( tokens, config ); + unusedTokens = populateFixedArgs( unusedTokens, config ); + unusedTokens = populateFloatingArgs( unusedTokens, config ); + return unusedTokens; + } + + std::vector populateOptions( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + std::vector errors; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); + for(; it != itEnd; ++it ) { + Arg const& arg = *it; + + try { + if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || + ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { + if( arg.takesArg() ) { + if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) + errors.push_back( "Expected argument to option: " + token.data ); + else + arg.boundField.set( config, tokens[++i].data ); + } + else { + arg.boundField.setFlag( config ); + } + break; + } + } + catch( std::exception& ex ) { + errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); + } + } + if( it == itEnd ) { + if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) + unusedTokens.push_back( token ); + else if( m_throwOnUnrecognisedTokens ) + errors.push_back( "unrecognised option: " + token.data ); + } + } + if( !errors.empty() ) { + std::ostringstream oss; + for( std::vector::const_iterator it = errors.begin(), itEnd = errors.end(); + it != itEnd; + ++it ) { + if( it != errors.begin() ) + oss << "\n"; + oss << *it; + } + throw std::runtime_error( oss.str() ); + } + return unusedTokens; + } + std::vector populateFixedArgs( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + int position = 1; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::map::const_iterator it = m_positionalArgs.find( position ); + if( it != m_positionalArgs.end() ) + it->second.boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + if( token.type == Parser::Token::Positional ) + position++; + } + return unusedTokens; + } + std::vector populateFloatingArgs( std::vector const& tokens, ConfigT& config ) const { + if( !m_floatingArg.get() ) + return tokens; + std::vector unusedTokens; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + if( token.type == Parser::Token::Positional ) + m_floatingArg->boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + } + return unusedTokens; + } + + void validate() const + { + if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) + throw std::logic_error( "No options or arguments specified" ); + + for( typename std::vector::const_iterator it = m_options.begin(), + itEnd = m_options.end(); + it != itEnd; ++it ) + it->validate(); + } + + private: + Detail::BoundArgFunction m_boundProcessName; + std::vector m_options; + std::map m_positionalArgs; + ArgAutoPtr m_floatingArg; + int m_highestSpecifiedArgPosition; + bool m_throwOnUnrecognisedTokens; + }; + +} // end namespace Clara + +STITCH_CLARA_CLOSE_NAMESPACE +#undef STITCH_CLARA_OPEN_NAMESPACE +#undef STITCH_CLARA_CLOSE_NAMESPACE + +#endif // TWOBLUECUBES_CLARA_H_INCLUDED +#undef STITCH_CLARA_OPEN_NAMESPACE + +// Restore Clara's value for console width, if present +#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +#include + +namespace Catch { + + inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } + inline void abortAfterX( ConfigData& config, int x ) { + if( x < 1 ) + throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); + config.abortAfter = x; + } + inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } + + inline void addWarning( ConfigData& config, std::string const& _warning ) { + if( _warning == "NoAssertions" ) + config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); + else + throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" ); + + } + inline void setVerbosity( ConfigData& config, int level ) { + // !TBD: accept strings? + config.verbosity = static_cast( level ); + } + inline void setShowDurations( ConfigData& config, bool _showDurations ) { + config.showDurations = _showDurations + ? ShowDurations::Always + : ShowDurations::Never; + } + inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { + std::ifstream f( _filename.c_str() ); + if( !f.is_open() ) + throw std::domain_error( "Unable to load input file: " + _filename ); + + std::string line; + while( std::getline( f, line ) ) { + line = trim(line); + if( !line.empty() && !startsWith( line, "#" ) ) + addTestOrTags( config, "\"" + line + "\"," ); + } + } + + inline Clara::CommandLine makeCommandLineParser() { + + using namespace Clara; + CommandLine cli; + + cli.bindProcessName( &ConfigData::processName ); + + cli["-?"]["-h"]["--help"] + .describe( "display usage information" ) + .bind( &ConfigData::showHelp ); + + cli["-l"]["--list-tests"] + .describe( "list all/matching test cases" ) + .bind( &ConfigData::listTests ); + + cli["-t"]["--list-tags"] + .describe( "list all/matching tags" ) + .bind( &ConfigData::listTags ); + + cli["-s"]["--success"] + .describe( "include successful tests in output" ) + .bind( &ConfigData::showSuccessfulTests ); + + cli["-b"]["--break"] + .describe( "break into debugger on failure" ) + .bind( &ConfigData::shouldDebugBreak ); + + cli["-e"]["--nothrow"] + .describe( "skip exception tests" ) + .bind( &ConfigData::noThrow ); + + cli["-i"]["--invisibles"] + .describe( "show invisibles (tabs, newlines)" ) + .bind( &ConfigData::showInvisibles ); + + cli["-o"]["--out"] + .describe( "output filename" ) + .bind( &ConfigData::outputFilename, "filename" ); + + cli["-r"]["--reporter"] +// .placeholder( "name[:filename]" ) + .describe( "reporter to use (defaults to console)" ) + .bind( &ConfigData::reporterName, "name" ); + + cli["-n"]["--name"] + .describe( "suite name" ) + .bind( &ConfigData::name, "name" ); + + cli["-a"]["--abort"] + .describe( "abort at first failure" ) + .bind( &abortAfterFirst ); + + cli["-x"]["--abortx"] + .describe( "abort after x failures" ) + .bind( &abortAfterX, "no. failures" ); + + cli["-w"]["--warn"] + .describe( "enable warnings" ) + .bind( &addWarning, "warning name" ); + +// - needs updating if reinstated +// cli.into( &setVerbosity ) +// .describe( "level of verbosity (0=no output)" ) +// .shortOpt( "v") +// .longOpt( "verbosity" ) +// .placeholder( "level" ); + + cli[_] + .describe( "which test or tests to use" ) + .bind( &addTestOrTags, "test name, pattern or tags" ); + + cli["-d"]["--durations"] + .describe( "show test durations" ) + .bind( &setShowDurations, "yes/no" ); + + cli["-f"]["--input-file"] + .describe( "load test names to run from a file" ) + .bind( &loadTestNamesFromFile, "filename" ); + + // Less common commands which don't have a short form + cli["--list-test-names-only"] + .describe( "list all/matching test cases names only" ) + .bind( &ConfigData::listTestNamesOnly ); + + cli["--list-reporters"] + .describe( "list all reporters" ) + .bind( &ConfigData::listReporters ); + + return cli; + } + +} // end namespace Catch + +// #included from: internal/catch_list.hpp +#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED + +// #included from: catch_text.h +#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED + +#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch +// #included from: ../external/tbc_text_format.h +// Only use header guard if we are not using an outer namespace +#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# endif +# else +# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# endif +#endif +#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#include +#include +#include + +// Use optional outer namespace +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE + +namespace Catch { + using Tbc::Text; + using Tbc::TextAttributes; +} + +// #included from: catch_console_colour.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED + +namespace Catch { + + namespace Detail { + struct IColourImpl; + } + + struct Colour { + enum Code { + None = 0, + + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, + + Bright = 0x10, + + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White, + + // By intention + FileName = LightGrey, + Warning = Yellow, + ResultError = BrightRed, + ResultSuccess = BrightGreen, + ResultExpectedFailure = Warning, + + Error = BrightRed, + Success = Green, + + OriginalExpression = Cyan, + ReconstructedExpression = Yellow, + + SecondaryText = LightGrey, + Headers = White + }; + + // Use constructed object for RAII guard + Colour( Code _colourCode ); + Colour( Colour const& other ); + ~Colour(); + + // Use static method for one-shot changes + static void use( Code _colourCode ); + + private: + static Detail::IColourImpl* impl(); + bool m_moved; + }; + + inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } + +} // end namespace Catch + +// #included from: catch_interfaces_reporter.h +#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED + +#include +#include +#include +#include + +namespace Catch +{ + struct ReporterConfig { + explicit ReporterConfig( Ptr const& _fullConfig ) + : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} + + ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) + : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} + + std::ostream& stream() const { return *m_stream; } + Ptr fullConfig() const { return m_fullConfig; } + + private: + std::ostream* m_stream; + Ptr m_fullConfig; + }; + + struct ReporterPreferences { + ReporterPreferences() + : shouldRedirectStdOut( false ) + {} + + bool shouldRedirectStdOut; + }; + + template + struct LazyStat : Option { + LazyStat() : used( false ) {} + LazyStat& operator=( T const& _value ) { + Option::operator=( _value ); + used = false; + return *this; + } + void reset() { + Option::reset(); + used = false; + } + bool used; + }; + + struct TestRunInfo { + TestRunInfo( std::string const& _name ) : name( _name ) {} + std::string name; + }; + struct GroupInfo { + GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ) + : name( _name ), + groupIndex( _groupIndex ), + groupsCounts( _groupsCount ) + {} + + std::string name; + std::size_t groupIndex; + std::size_t groupsCounts; + }; + + struct AssertionStats { + AssertionStats( AssertionResult const& _assertionResult, + std::vector const& _infoMessages, + Totals const& _totals ) + : assertionResult( _assertionResult ), + infoMessages( _infoMessages ), + totals( _totals ) + { + if( assertionResult.hasMessage() ) { + // Copy message into messages list. + // !TBD This should have been done earlier, somewhere + MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); + builder << assertionResult.getMessage(); + builder.m_info.message = builder.m_stream.str(); + + infoMessages.push_back( builder.m_info ); + } + } + virtual ~AssertionStats(); + +# ifdef CATCH_CPP11_OR_GREATER + AssertionStats( AssertionStats const& ) = default; + AssertionStats( AssertionStats && ) = default; + AssertionStats& operator = ( AssertionStats const& ) = default; + AssertionStats& operator = ( AssertionStats && ) = default; +# endif + + AssertionResult assertionResult; + std::vector infoMessages; + Totals totals; + }; + + struct SectionStats { + SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ) + : sectionInfo( _sectionInfo ), + assertions( _assertions ), + durationInSeconds( _durationInSeconds ), + missingAssertions( _missingAssertions ) + {} + virtual ~SectionStats(); +# ifdef CATCH_CPP11_OR_GREATER + SectionStats( SectionStats const& ) = default; + SectionStats( SectionStats && ) = default; + SectionStats& operator = ( SectionStats const& ) = default; + SectionStats& operator = ( SectionStats && ) = default; +# endif + + SectionInfo sectionInfo; + Counts assertions; + double durationInSeconds; + bool missingAssertions; + }; + + struct TestCaseStats { + TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ) + : testInfo( _testInfo ), + totals( _totals ), + stdOut( _stdOut ), + stdErr( _stdErr ), + aborting( _aborting ) + {} + virtual ~TestCaseStats(); + +# ifdef CATCH_CPP11_OR_GREATER + TestCaseStats( TestCaseStats const& ) = default; + TestCaseStats( TestCaseStats && ) = default; + TestCaseStats& operator = ( TestCaseStats const& ) = default; + TestCaseStats& operator = ( TestCaseStats && ) = default; +# endif + + TestCaseInfo testInfo; + Totals totals; + std::string stdOut; + std::string stdErr; + bool aborting; + }; + + struct TestGroupStats { + TestGroupStats( GroupInfo const& _groupInfo, + Totals const& _totals, + bool _aborting ) + : groupInfo( _groupInfo ), + totals( _totals ), + aborting( _aborting ) + {} + TestGroupStats( GroupInfo const& _groupInfo ) + : groupInfo( _groupInfo ), + aborting( false ) + {} + virtual ~TestGroupStats(); + +# ifdef CATCH_CPP11_OR_GREATER + TestGroupStats( TestGroupStats const& ) = default; + TestGroupStats( TestGroupStats && ) = default; + TestGroupStats& operator = ( TestGroupStats const& ) = default; + TestGroupStats& operator = ( TestGroupStats && ) = default; +# endif + + GroupInfo groupInfo; + Totals totals; + bool aborting; + }; + + struct TestRunStats { + TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ) + : runInfo( _runInfo ), + totals( _totals ), + aborting( _aborting ) + {} + virtual ~TestRunStats(); + +# ifndef CATCH_CPP11_OR_GREATER + TestRunStats( TestRunStats const& _other ) + : runInfo( _other.runInfo ), + totals( _other.totals ), + aborting( _other.aborting ) + {} +# else + TestRunStats( TestRunStats const& ) = default; + TestRunStats( TestRunStats && ) = default; + TestRunStats& operator = ( TestRunStats const& ) = default; + TestRunStats& operator = ( TestRunStats && ) = default; +# endif + + TestRunInfo runInfo; + Totals totals; + bool aborting; + }; + + struct IStreamingReporter : IShared { + virtual ~IStreamingReporter(); + + // Implementing class must also provide the following static method: + // static std::string getDescription(); + + virtual ReporterPreferences getPreferences() const = 0; + + virtual void noMatchingTestCases( std::string const& spec ) = 0; + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; + virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; + virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; + + virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; + virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; + }; + + struct IReporterFactory { + virtual ~IReporterFactory(); + virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; + virtual std::string getDescription() const = 0; + }; + + struct IReporterRegistry { + typedef std::map FactoryMap; + + virtual ~IReporterRegistry(); + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; + virtual FactoryMap const& getFactories() const = 0; + }; + +} + +#include +#include + +namespace Catch { + + inline std::size_t listTests( Config const& config ) { + + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + std::cout << "Matching test cases:\n"; + else { + std::cout << "All available test cases:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::size_t matchedTests = 0; + TextAttributes nameAttr, tagsAttr; + nameAttr.setInitialIndent( 2 ).setIndent( 4 ); + tagsAttr.setIndent( 6 ); + + std::vector matchedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Colour::Code colour = testCaseInfo.isHidden() + ? Colour::SecondaryText + : Colour::None; + Colour colourGuard( colour ); + + std::cout << Text( testCaseInfo.name, nameAttr ) << std::endl; + if( !testCaseInfo.tags.empty() ) + std::cout << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; + } + + if( !config.testSpec().hasFilters() ) + std::cout << pluralise( matchedTests, "test case" ) << "\n" << std::endl; + else + std::cout << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl; + return matchedTests; + } + + inline std::size_t listTestsNamesOnly( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( !config.testSpec().hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + std::size_t matchedTests = 0; + std::vector matchedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + std::cout << testCaseInfo.name << std::endl; + } + return matchedTests; + } + + struct TagInfo { + TagInfo() : count ( 0 ) {} + void add( std::string const& spelling ) { + ++count; + spellings.insert( spelling ); + } + std::string all() const { + std::string out; + for( std::set::const_iterator it = spellings.begin(), itEnd = spellings.end(); + it != itEnd; + ++it ) + out += "[" + *it + "]"; + return out; + } + std::set spellings; + std::size_t count; + }; + + inline std::size_t listTags( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + std::cout << "Tags for matching test cases:\n"; + else { + std::cout << "All available tags:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::map tagCounts; + + std::vector matchedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + for( std::set::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), + tagItEnd = it->getTestCaseInfo().tags.end(); + tagIt != tagItEnd; + ++tagIt ) { + std::string tagName = *tagIt; + std::string lcaseTagName = toLower( tagName ); + std::map::iterator countIt = tagCounts.find( lcaseTagName ); + if( countIt == tagCounts.end() ) + countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; + countIt->second.add( tagName ); + } + } + + for( std::map::const_iterator countIt = tagCounts.begin(), + countItEnd = tagCounts.end(); + countIt != countItEnd; + ++countIt ) { + std::ostringstream oss; + oss << " " << std::setw(2) << countIt->second.count << " "; + Text wrapper( countIt->second.all(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( oss.str().size() ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); + std::cout << oss.str() << wrapper << "\n"; + } + std::cout << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl; + return tagCounts.size(); + } + + inline std::size_t listReporters( Config const& /*config*/ ) { + std::cout << "Available reports:\n"; + IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; + std::size_t maxNameLen = 0; + for(it = itBegin; it != itEnd; ++it ) + maxNameLen = (std::max)( maxNameLen, it->first.size() ); + + for(it = itBegin; it != itEnd; ++it ) { + Text wrapper( it->second->getDescription(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( 7+maxNameLen ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); + std::cout << " " + << it->first + << ":" + << std::string( maxNameLen - it->first.size() + 2, ' ' ) + << wrapper << "\n"; + } + std::cout << std::endl; + return factories.size(); + } + + inline Option list( Config const& config ) { + Option listedCount; + if( config.listTests() ) + listedCount = listedCount.valueOr(0) + listTests( config ); + if( config.listTestNamesOnly() ) + listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); + if( config.listTags() ) + listedCount = listedCount.valueOr(0) + listTags( config ); + if( config.listReporters() ) + listedCount = listedCount.valueOr(0) + listReporters( config ); + return listedCount; + } + +} // end namespace Catch + +// #included from: internal/catch_runner_impl.hpp +#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED + +// #included from: catch_test_case_tracker.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { +namespace SectionTracking { + + class TrackedSection { + + typedef std::map TrackedSections; + + public: + enum RunState { + NotStarted, + Executing, + ExecutingChildren, + Completed + }; + + TrackedSection( std::string const& name, TrackedSection* parent ) + : m_name( name ), m_runState( NotStarted ), m_parent( parent ) + {} + + RunState runState() const { return m_runState; } + + TrackedSection* findChild( std::string const& childName ) { + TrackedSections::iterator it = m_children.find( childName ); + return it != m_children.end() + ? &it->second + : NULL; + } + TrackedSection* acquireChild( std::string const& childName ) { + if( TrackedSection* child = findChild( childName ) ) + return child; + m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) ); + return findChild( childName ); + } + void enter() { + if( m_runState == NotStarted ) + m_runState = Executing; + } + void leave() { + for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end(); + it != itEnd; + ++it ) + if( it->second.runState() != Completed ) { + m_runState = ExecutingChildren; + return; + } + m_runState = Completed; + } + TrackedSection* getParent() { + return m_parent; + } + bool hasChildren() const { + return !m_children.empty(); + } + + private: + std::string m_name; + RunState m_runState; + TrackedSections m_children; + TrackedSection* m_parent; + + }; + + class TestCaseTracker { + public: + TestCaseTracker( std::string const& testCaseName ) + : m_testCase( testCaseName, NULL ), + m_currentSection( &m_testCase ), + m_completedASectionThisRun( false ) + {} + + bool enterSection( std::string const& name ) { + TrackedSection* child = m_currentSection->acquireChild( name ); + if( m_completedASectionThisRun || child->runState() == TrackedSection::Completed ) + return false; + + m_currentSection = child; + m_currentSection->enter(); + return true; + } + void leaveSection() { + m_currentSection->leave(); + m_currentSection = m_currentSection->getParent(); + assert( m_currentSection != NULL ); + m_completedASectionThisRun = true; + } + + bool currentSectionHasChildren() const { + return m_currentSection->hasChildren(); + } + bool isCompleted() const { + return m_testCase.runState() == TrackedSection::Completed; + } + + class Guard { + public: + Guard( TestCaseTracker& tracker ) : m_tracker( tracker ) { + m_tracker.enterTestCase(); + } + ~Guard() { + m_tracker.leaveTestCase(); + } + private: + Guard( Guard const& ); + void operator = ( Guard const& ); + TestCaseTracker& m_tracker; + }; + + private: + void enterTestCase() { + m_currentSection = &m_testCase; + m_completedASectionThisRun = false; + m_testCase.enter(); + } + void leaveTestCase() { + m_testCase.leave(); + } + + TrackedSection m_testCase; + TrackedSection* m_currentSection; + bool m_completedASectionThisRun; + }; + +} // namespace SectionTracking + +using SectionTracking::TestCaseTracker; + +} // namespace Catch + +#include +#include + +namespace Catch { + + class StreamRedirect { + + public: + StreamRedirect( std::ostream& stream, std::string& targetString ) + : m_stream( stream ), + m_prevBuf( stream.rdbuf() ), + m_targetString( targetString ) + { + stream.rdbuf( m_oss.rdbuf() ); + } + + ~StreamRedirect() { + m_targetString += m_oss.str(); + m_stream.rdbuf( m_prevBuf ); + } + + private: + std::ostream& m_stream; + std::streambuf* m_prevBuf; + std::ostringstream m_oss; + std::string& m_targetString; + }; + + /////////////////////////////////////////////////////////////////////////// + + class RunContext : public IResultCapture, public IRunner { + + RunContext( RunContext const& ); + void operator =( RunContext const& ); + + public: + + explicit RunContext( Ptr const& config, Ptr const& reporter ) + : m_runInfo( config->name() ), + m_context( getCurrentMutableContext() ), + m_activeTestCase( NULL ), + m_config( config ), + m_reporter( reporter ), + m_prevRunner( m_context.getRunner() ), + m_prevResultCapture( m_context.getResultCapture() ), + m_prevConfig( m_context.getConfig() ) + { + m_context.setRunner( this ); + m_context.setConfig( m_config ); + m_context.setResultCapture( this ); + m_reporter->testRunStarting( m_runInfo ); + } + + virtual ~RunContext() { + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); + m_context.setRunner( m_prevRunner ); + m_context.setConfig( NULL ); + m_context.setResultCapture( m_prevResultCapture ); + m_context.setConfig( m_prevConfig ); + } + + void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); + } + void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); + } + + Totals runTest( TestCase const& testCase ) { + Totals prevTotals = m_totals; + + std::string redirectedCout; + std::string redirectedCerr; + + TestCaseInfo testInfo = testCase.getTestCaseInfo(); + + m_reporter->testCaseStarting( testInfo ); + + m_activeTestCase = &testCase; + m_testCaseTracker = TestCaseTracker( testInfo.name ); + + do { + do { + runCurrentTest( redirectedCout, redirectedCerr ); + } + while( !m_testCaseTracker->isCompleted() && !aborting() ); + } + while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); + + Totals deltaTotals = m_totals.delta( prevTotals ); + m_totals.testCases += deltaTotals.testCases; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + redirectedCout, + redirectedCerr, + aborting() ) ); + + m_activeTestCase = NULL; + m_testCaseTracker.reset(); + + return deltaTotals; + } + + Ptr config() const { + return m_config; + } + + private: // IResultCapture + + virtual void assertionEnded( AssertionResult const& result ) { + if( result.getResultType() == ResultWas::Ok ) { + m_totals.assertions.passed++; + } + else if( !result.isOk() ) { + m_totals.assertions.failed++; + } + + if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) ) + m_messages.clear(); + + // Reset working state + m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); + m_lastResult = result; + } + + virtual bool sectionStarted ( + SectionInfo const& sectionInfo, + Counts& assertions + ) + { + std::ostringstream oss; + oss << sectionInfo.name << "@" << sectionInfo.lineInfo; + + if( !m_testCaseTracker->enterSection( oss.str() ) ) + return false; + + m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; + + m_reporter->sectionStarting( sectionInfo ); + + assertions = m_totals.assertions; + + return true; + } + bool testForMissingAssertions( Counts& assertions ) { + if( assertions.total() != 0 || + !m_config->warnAboutMissingAssertions() || + m_testCaseTracker->currentSectionHasChildren() ) + return false; + m_totals.assertions.failed++; + assertions.failed++; + return true; + } + + virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) { + if( std::uncaught_exception() ) { + m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) ); + return; + } + + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + m_testCaseTracker->leaveSection(); + + m_reporter->sectionEnded( SectionStats( info, assertions, _durationInSeconds, missingAssertions ) ); + m_messages.clear(); + } + + virtual void pushScopedMessage( MessageInfo const& message ) { + m_messages.push_back( message ); + } + + virtual void popScopedMessage( MessageInfo const& message ) { + m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); + } + + virtual std::string getCurrentTestName() const { + return m_activeTestCase + ? m_activeTestCase->getTestCaseInfo().name + : ""; + } + + virtual const AssertionResult* getLastResult() const { + return &m_lastResult; + } + + public: + // !TBD We need to do this another way! + bool aborting() const { + return m_totals.assertions.failed == static_cast( m_config->abortAfter() ); + } + + private: + + void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + m_reporter->sectionStarting( testCaseSection ); + Counts prevAssertions = m_totals.assertions; + double duration = 0; + try { + m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); + TestCaseTracker::Guard guard( *m_testCaseTracker ); + + Timer timer; + timer.start(); + if( m_reporter->getPreferences().shouldRedirectStdOut ) { + StreamRedirect coutRedir( std::cout, redirectedCout ); + StreamRedirect cerrRedir( std::cerr, redirectedCerr ); + m_activeTestCase->invoke(); + } + else { + m_activeTestCase->invoke(); + } + duration = timer.getElapsedSeconds(); + } + catch( TestFailureException& ) { + // This just means the test was aborted due to failure + } + catch(...) { + ResultBuilder exResult( m_lastAssertionInfo.macroName.c_str(), + m_lastAssertionInfo.lineInfo, + m_lastAssertionInfo.capturedExpression.c_str(), + m_lastAssertionInfo.resultDisposition ); + exResult.useActiveException(); + } + // If sections ended prematurely due to an exception we stored their + // infos here so we can tear them down outside the unwind process. + for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), + itEnd = m_unfinishedSections.rend(); + it != itEnd; + ++it ) + sectionEnded( it->info, it->prevAssertions, it->durationInSeconds ); + m_unfinishedSections.clear(); + m_messages.clear(); + + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( testCaseInfo.okToFail() ) { + std::swap( assertions.failedButOk, assertions.failed ); + m_totals.assertions.failed -= assertions.failedButOk; + m_totals.assertions.failedButOk += assertions.failedButOk; + } + + SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); + m_reporter->sectionEnded( testCaseSectionStats ); + } + + private: + struct UnfinishedSections { + UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds ) + : info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) + {} + + SectionInfo info; + Counts prevAssertions; + double durationInSeconds; + }; + + TestRunInfo m_runInfo; + IMutableContext& m_context; + TestCase const* m_activeTestCase; + Option m_testCaseTracker; + AssertionResult m_lastResult; + + Ptr m_config; + Totals m_totals; + Ptr m_reporter; + std::vector m_messages; + IRunner* m_prevRunner; + IResultCapture* m_prevResultCapture; + Ptr m_prevConfig; + AssertionInfo m_lastAssertionInfo; + std::vector m_unfinishedSections; + }; + + IResultCapture& getResultCapture() { + if( IResultCapture* capture = getCurrentContext().getResultCapture() ) + return *capture; + else + throw std::logic_error( "No result capture instance" ); + } + +} // end namespace Catch + +// #included from: internal/catch_version.h +#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED + +namespace Catch { + + // Versioning information + struct Version { + Version( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _buildNumber, + char const* const _branchName ) + : majorVersion( _majorVersion ), + minorVersion( _minorVersion ), + buildNumber( _buildNumber ), + branchName( _branchName ) + {} + + unsigned int const majorVersion; + unsigned int const minorVersion; + unsigned int const buildNumber; + char const* const branchName; + + private: + void operator=( Version const& ); + }; + + extern Version libraryVersion; +} + +#include +#include +#include + +namespace Catch { + + class Runner { + + public: + Runner( Ptr const& config ) + : m_config( config ) + { + openStream(); + makeReporter(); + } + + Totals runTests() { + + RunContext context( m_config.get(), m_reporter ); + + Totals totals; + + context.testGroupStarting( "", 1, 1 ); // deprecated? + + TestSpec testSpec = m_config->testSpec(); + if( !testSpec.hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests + + std::vector testCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, testCases ); + + int testsRunForGroup = 0; + for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); + it != itEnd; + ++it ) { + testsRunForGroup++; + if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) { + + if( context.aborting() ) + break; + + totals += context.runTest( *it ); + m_testsAlreadyRun.insert( *it ); + } + } + context.testGroupEnded( "", totals, 1, 1 ); + return totals; + } + + private: + void openStream() { + // Open output file, if specified + if( !m_config->getFilename().empty() ) { + m_ofs.open( m_config->getFilename().c_str() ); + if( m_ofs.fail() ) { + std::ostringstream oss; + oss << "Unable to open file: '" << m_config->getFilename() << "'"; + throw std::domain_error( oss.str() ); + } + m_config->setStreamBuf( m_ofs.rdbuf() ); + } + } + void makeReporter() { + std::string reporterName = m_config->getReporterName().empty() + ? "console" + : m_config->getReporterName(); + + m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, m_config.get() ); + if( !m_reporter ) { + std::ostringstream oss; + oss << "No reporter registered with name: '" << reporterName << "'"; + throw std::domain_error( oss.str() ); + } + } + + private: + Ptr m_config; + std::ofstream m_ofs; + Ptr m_reporter; + std::set m_testsAlreadyRun; + }; + + class Session { + static bool alreadyInstantiated; + + public: + + struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; + + Session() + : m_cli( makeCommandLineParser() ) { + if( alreadyInstantiated ) { + std::string msg = "Only one instance of Catch::Session can ever be used"; + std::cerr << msg << std::endl; + throw std::logic_error( msg ); + } + alreadyInstantiated = true; + } + ~Session() { + Catch::cleanUp(); + } + + void showHelp( std::string const& processName ) { + std::cout << "\nCatch v" << libraryVersion.majorVersion << "." + << libraryVersion.minorVersion << " build " + << libraryVersion.buildNumber; + if( libraryVersion.branchName != std::string( "master" ) ) + std::cout << " (" << libraryVersion.branchName << " branch)"; + std::cout << "\n"; + + m_cli.usage( std::cout, processName ); + std::cout << "For more detail usage please see the project docs\n" << std::endl; + } + + int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { + try { + m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); + m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); + if( m_configData.showHelp ) + showHelp( m_configData.processName ); + m_config.reset(); + } + catch( std::exception& ex ) { + { + Colour colourGuard( Colour::Red ); + std::cerr << "\nError(s) in input:\n" + << Text( ex.what(), TextAttributes().setIndent(2) ) + << "\n\n"; + } + m_cli.usage( std::cout, m_configData.processName ); + return (std::numeric_limits::max)(); + } + return 0; + } + + void useConfigData( ConfigData const& _configData ) { + m_configData = _configData; + m_config.reset(); + } + + int run( int argc, char* const argv[] ) { + + int returnCode = applyCommandLine( argc, argv ); + if( returnCode == 0 ) + returnCode = run(); + return returnCode; + } + + int run() { + if( m_configData.showHelp ) + return 0; + + try + { + config(); // Force config to be constructed + Runner runner( m_config ); + + // Handle list request + if( Option listed = list( config() ) ) + return static_cast( *listed ); + + return static_cast( runner.runTests().assertions.failed ); + } + catch( std::exception& ex ) { + std::cerr << ex.what() << std::endl; + return (std::numeric_limits::max)(); + } + } + + Clara::CommandLine const& cli() const { + return m_cli; + } + std::vector const& unusedTokens() const { + return m_unusedTokens; + } + ConfigData& configData() { + return m_configData; + } + Config& config() { + if( !m_config ) + m_config = new Config( m_configData ); + return *m_config; + } + + private: + Clara::CommandLine m_cli; + std::vector m_unusedTokens; + ConfigData m_configData; + Ptr m_config; + }; + + bool Session::alreadyInstantiated = false; + +} // end namespace Catch + +// #included from: catch_registry_hub.hpp +#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED + +// #included from: catch_test_case_registry_impl.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + + class TestRegistry : public ITestCaseRegistry { + public: + TestRegistry() : m_unnamedCount( 0 ) {} + virtual ~TestRegistry(); + + virtual void registerTest( TestCase const& testCase ) { + std::string name = testCase.getTestCaseInfo().name; + if( name == "" ) { + std::ostringstream oss; + oss << "Anonymous test case " << ++m_unnamedCount; + return registerTest( testCase.withName( oss.str() ) ); + } + + if( m_functions.find( testCase ) == m_functions.end() ) { + m_functions.insert( testCase ); + m_functionsInOrder.push_back( testCase ); + if( !testCase.isHidden() ) + m_nonHiddenFunctions.push_back( testCase ); + } + else { + TestCase const& prev = *m_functions.find( testCase ); + { + Colour colourGuard( Colour::Red ); + std::cerr << "error: TEST_CASE( \"" << name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << testCase.getTestCaseInfo().lineInfo << std::endl; + } + exit(1); + } + } + + virtual std::vector const& getAllTests() const { + return m_functionsInOrder; + } + + virtual std::vector const& getAllNonHiddenTests() const { + return m_nonHiddenFunctions; + } + + virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases ) const { + for( std::vector::const_iterator it = m_functionsInOrder.begin(), + itEnd = m_functionsInOrder.end(); + it != itEnd; + ++it ) { + if( testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() ) ) + matchingTestCases.push_back( *it ); + } + } + + private: + + std::set m_functions; + std::vector m_functionsInOrder; + std::vector m_nonHiddenFunctions; + size_t m_unnamedCount; + }; + + /////////////////////////////////////////////////////////////////////////// + + class FreeFunctionTestCase : public SharedImpl { + public: + + FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} + + virtual void invoke() const { + m_fun(); + } + + private: + virtual ~FreeFunctionTestCase(); + + TestFunction m_fun; + }; + + inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { + std::string className = classOrQualifiedMethodName; + if( startsWith( className, "&" ) ) + { + std::size_t lastColons = className.rfind( "::" ); + std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); + if( penultimateColons == std::string::npos ) + penultimateColons = 1; + className = className.substr( penultimateColons, lastColons-penultimateColons ); + } + return className; + } + + /////////////////////////////////////////////////////////////////////////// + + AutoReg::AutoReg( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); + } + + AutoReg::~AutoReg() {} + + void AutoReg::registerTestCase( ITestCase* testCase, + char const* classOrQualifiedMethodName, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + getMutableRegistryHub().registerTest + ( makeTestCase( testCase, + extractClassName( classOrQualifiedMethodName ), + nameAndDesc.name, + nameAndDesc.description, + lineInfo ) ); + } + +} // end namespace Catch + +// #included from: catch_reporter_registry.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED + +#include + +namespace Catch { + + class ReporterRegistry : public IReporterRegistry { + + public: + + virtual ~ReporterRegistry() { + deleteAllValues( m_factories ); + } + + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const { + FactoryMap::const_iterator it = m_factories.find( name ); + if( it == m_factories.end() ) + return NULL; + return it->second->create( ReporterConfig( config ) ); + } + + void registerReporter( std::string const& name, IReporterFactory* factory ) { + m_factories.insert( std::make_pair( name, factory ) ); + } + + FactoryMap const& getFactories() const { + return m_factories; + } + + private: + FactoryMap m_factories; + }; +} + +// #included from: catch_exception_translator_registry.hpp +#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED + +#ifdef __OBJC__ +#import "Foundation/Foundation.h" +#endif + +namespace Catch { + + class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { + public: + ~ExceptionTranslatorRegistry() { + deleteAll( m_translators ); + } + + virtual void registerTranslator( const IExceptionTranslator* translator ) { + m_translators.push_back( translator ); + } + + virtual std::string translateActiveException() const { + try { +#ifdef __OBJC__ + // In Objective-C try objective-c exceptions first + @try { + throw; + } + @catch (NSException *exception) { + return toString( [exception description] ); + } +#else + throw; +#endif + } + catch( TestFailureException& ) { + throw; + } + catch( std::exception& ex ) { + return ex.what(); + } + catch( std::string& msg ) { + return msg; + } + catch( const char* msg ) { + return msg; + } + catch(...) { + return tryTranslators( m_translators.begin() ); + } + } + + std::string tryTranslators( std::vector::const_iterator it ) const { + if( it == m_translators.end() ) + return "Unknown exception"; + + try { + return (*it)->translate(); + } + catch(...) { + return tryTranslators( it+1 ); + } + } + + private: + std::vector m_translators; + }; +} + +namespace Catch { + + namespace { + + class RegistryHub : public IRegistryHub, public IMutableRegistryHub { + + RegistryHub( RegistryHub const& ); + void operator=( RegistryHub const& ); + + public: // IRegistryHub + RegistryHub() { + } + virtual IReporterRegistry const& getReporterRegistry() const { + return m_reporterRegistry; + } + virtual ITestCaseRegistry const& getTestCaseRegistry() const { + return m_testCaseRegistry; + } + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() { + return m_exceptionTranslatorRegistry; + } + + public: // IMutableRegistryHub + virtual void registerReporter( std::string const& name, IReporterFactory* factory ) { + m_reporterRegistry.registerReporter( name, factory ); + } + virtual void registerTest( TestCase const& testInfo ) { + m_testCaseRegistry.registerTest( testInfo ); + } + virtual void registerTranslator( const IExceptionTranslator* translator ) { + m_exceptionTranslatorRegistry.registerTranslator( translator ); + } + + private: + TestRegistry m_testCaseRegistry; + ReporterRegistry m_reporterRegistry; + ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; + }; + + // Single, global, instance + inline RegistryHub*& getTheRegistryHub() { + static RegistryHub* theRegistryHub = NULL; + if( !theRegistryHub ) + theRegistryHub = new RegistryHub(); + return theRegistryHub; + } + } + + IRegistryHub& getRegistryHub() { + return *getTheRegistryHub(); + } + IMutableRegistryHub& getMutableRegistryHub() { + return *getTheRegistryHub(); + } + void cleanUp() { + delete getTheRegistryHub(); + getTheRegistryHub() = NULL; + cleanUpContext(); + } + std::string translateActiveException() { + return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); + } + +} // end namespace Catch + +// #included from: catch_notimplemented_exception.hpp +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED + +#include + +namespace Catch { + + NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) + : m_lineInfo( lineInfo ) { + std::ostringstream oss; + oss << lineInfo << ": function "; + oss << "not implemented"; + m_what = oss.str(); + } + + const char* NotImplementedException::what() const CATCH_NOEXCEPT { + return m_what.c_str(); + } + +} // end namespace Catch + +// #included from: catch_context_impl.hpp +#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED + +// #included from: catch_stream.hpp +#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED + +// #included from: catch_streambuf.h +#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED + +#include + +namespace Catch { + + class StreamBufBase : public std::streambuf { + public: + virtual ~StreamBufBase() CATCH_NOEXCEPT; + }; +} + +#include +#include + +namespace Catch { + + template + class StreamBufImpl : public StreamBufBase { + char data[bufferSize]; + WriterF m_writer; + + public: + StreamBufImpl() { + setp( data, data + sizeof(data) ); + } + + ~StreamBufImpl() CATCH_NOEXCEPT { + sync(); + } + + private: + int overflow( int c ) { + sync(); + + if( c != EOF ) { + if( pbase() == epptr() ) + m_writer( std::string( 1, static_cast( c ) ) ); + else + sputc( static_cast( c ) ); + } + return 0; + } + + int sync() { + if( pbase() != pptr() ) { + m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); + setp( pbase(), epptr() ); + } + return 0; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + struct OutputDebugWriter { + + void operator()( std::string const&str ) { + writeToDebugConsole( str ); + } + }; + + Stream::Stream() + : streamBuf( NULL ), isOwned( false ) + {} + + Stream::Stream( std::streambuf* _streamBuf, bool _isOwned ) + : streamBuf( _streamBuf ), isOwned( _isOwned ) + {} + + void Stream::release() { + if( isOwned ) { + delete streamBuf; + streamBuf = NULL; + isOwned = false; + } + } +} + +namespace Catch { + + class Context : public IMutableContext { + + Context() : m_config( NULL ), m_runner( NULL ), m_resultCapture( NULL ) {} + Context( Context const& ); + void operator=( Context const& ); + + public: // IContext + virtual IResultCapture* getResultCapture() { + return m_resultCapture; + } + virtual IRunner* getRunner() { + return m_runner; + } + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { + return getGeneratorsForCurrentTest() + .getGeneratorInfo( fileInfo, totalSize ) + .getCurrentIndex(); + } + virtual bool advanceGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + return generators && generators->moveNext(); + } + + virtual Ptr getConfig() const { + return m_config; + } + + public: // IMutableContext + virtual void setResultCapture( IResultCapture* resultCapture ) { + m_resultCapture = resultCapture; + } + virtual void setRunner( IRunner* runner ) { + m_runner = runner; + } + virtual void setConfig( Ptr const& config ) { + m_config = config; + } + + friend IMutableContext& getCurrentMutableContext(); + + private: + IGeneratorsForTest* findGeneratorsForCurrentTest() { + std::string testName = getResultCapture()->getCurrentTestName(); + + std::map::const_iterator it = + m_generatorsByTestName.find( testName ); + return it != m_generatorsByTestName.end() + ? it->second + : NULL; + } + + IGeneratorsForTest& getGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + if( !generators ) { + std::string testName = getResultCapture()->getCurrentTestName(); + generators = createGeneratorsForTest(); + m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); + } + return *generators; + } + + private: + Ptr m_config; + IRunner* m_runner; + IResultCapture* m_resultCapture; + std::map m_generatorsByTestName; + }; + + namespace { + Context* currentContext = NULL; + } + IMutableContext& getCurrentMutableContext() { + if( !currentContext ) + currentContext = new Context(); + return *currentContext; + } + IContext& getCurrentContext() { + return getCurrentMutableContext(); + } + + Stream createStream( std::string const& streamName ) { + if( streamName == "stdout" ) return Stream( std::cout.rdbuf(), false ); + if( streamName == "stderr" ) return Stream( std::cerr.rdbuf(), false ); + if( streamName == "debug" ) return Stream( new StreamBufImpl, true ); + + throw std::domain_error( "Unknown stream: " + streamName ); + } + + void cleanUpContext() { + delete currentContext; + currentContext = NULL; + } +} + +// #included from: catch_console_colour_impl.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED + +namespace Catch { namespace Detail { + struct IColourImpl { + virtual ~IColourImpl() {} + virtual void use( Colour::Code _colourCode ) = 0; + }; +}} + +#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#ifdef __AFXDLL +#include +#else +#include +#endif + +namespace Catch { +namespace { + + class Win32ColourImpl : public Detail::IColourImpl { + public: + Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) + { + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); + originalAttributes = csbiInfo.wAttributes; + } + + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: return setTextAttribute( originalAttributes ); + case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + case Colour::Red: return setTextAttribute( FOREGROUND_RED ); + case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); + case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); + case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); + case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); + case Colour::Grey: return setTextAttribute( 0 ); + + case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); + case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); + case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); + case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + + private: + void setTextAttribute( WORD _textAttribute ) { + SetConsoleTextAttribute( stdoutHandle, _textAttribute ); + } + HANDLE stdoutHandle; + WORD originalAttributes; + }; + + inline bool shouldUseColourForPlatform() { + return true; + } + + static Detail::IColourImpl* platformColourInstance() { + static Win32ColourImpl s_instance; + return &s_instance; + } + +} // end anon namespace +} // end namespace Catch + +#else // Not Windows - assumed to be POSIX compatible ////////////////////////// + +#include + +namespace Catch { +namespace { + + // use POSIX/ ANSI console terminal codes + // Thanks to Adam Strzelecki for original contribution + // (http://github.com/nanoant) + // https://github.com/philsquared/Catch/pull/131 + class PosixColourImpl : public Detail::IColourImpl { + public: + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: + case Colour::White: return setColour( "[0m" ); + case Colour::Red: return setColour( "[0;31m" ); + case Colour::Green: return setColour( "[0;32m" ); + case Colour::Blue: return setColour( "[0:34m" ); + case Colour::Cyan: return setColour( "[0;36m" ); + case Colour::Yellow: return setColour( "[0;33m" ); + case Colour::Grey: return setColour( "[1;30m" ); + + case Colour::LightGrey: return setColour( "[0;37m" ); + case Colour::BrightRed: return setColour( "[1;31m" ); + case Colour::BrightGreen: return setColour( "[1;32m" ); + case Colour::BrightWhite: return setColour( "[1;37m" ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + private: + void setColour( const char* _escapeCode ) { + std::cout << '\033' << _escapeCode; + } + }; + + inline bool shouldUseColourForPlatform() { + return isatty(STDOUT_FILENO); + } + + static Detail::IColourImpl* platformColourInstance() { + static PosixColourImpl s_instance; + return &s_instance; + } + +} // end anon namespace +} // end namespace Catch + +#endif // not Windows + +namespace Catch { + + namespace { + struct NoColourImpl : Detail::IColourImpl { + void use( Colour::Code ) {} + + static IColourImpl* instance() { + static NoColourImpl s_instance; + return &s_instance; + } + }; + static bool shouldUseColour() { + return shouldUseColourForPlatform() && !isDebuggerActive(); + } + } + + Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } + Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast( _other ).m_moved = true; } + Colour::~Colour(){ if( !m_moved ) use( None ); } + void Colour::use( Code _colourCode ) { + impl()->use( _colourCode ); + } + + Detail::IColourImpl* Colour::impl() { + return shouldUseColour() + ? platformColourInstance() + : NoColourImpl::instance(); + } + +} // end namespace Catch + +// #included from: catch_generators_impl.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { + + struct GeneratorInfo : IGeneratorInfo { + + GeneratorInfo( std::size_t size ) + : m_size( size ), + m_currentIndex( 0 ) + {} + + bool moveNext() { + if( ++m_currentIndex == m_size ) { + m_currentIndex = 0; + return false; + } + return true; + } + + std::size_t getCurrentIndex() const { + return m_currentIndex; + } + + std::size_t m_size; + std::size_t m_currentIndex; + }; + + /////////////////////////////////////////////////////////////////////////// + + class GeneratorsForTest : public IGeneratorsForTest { + + public: + ~GeneratorsForTest() { + deleteAll( m_generatorsInOrder ); + } + + IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { + std::map::const_iterator it = m_generatorsByName.find( fileInfo ); + if( it == m_generatorsByName.end() ) { + IGeneratorInfo* info = new GeneratorInfo( size ); + m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); + m_generatorsInOrder.push_back( info ); + return *info; + } + return *it->second; + } + + bool moveNext() { + std::vector::const_iterator it = m_generatorsInOrder.begin(); + std::vector::const_iterator itEnd = m_generatorsInOrder.end(); + for(; it != itEnd; ++it ) { + if( (*it)->moveNext() ) + return true; + } + return false; + } + + private: + std::map m_generatorsByName; + std::vector m_generatorsInOrder; + }; + + IGeneratorsForTest* createGeneratorsForTest() + { + return new GeneratorsForTest(); + } + +} // end namespace Catch + +// #included from: catch_assertionresult.hpp +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED + +namespace Catch { + + AssertionInfo::AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + capturedExpression( _capturedExpression ), + resultDisposition( _resultDisposition ) + {} + + AssertionResult::AssertionResult() {} + + AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) + : m_info( info ), + m_resultData( data ) + {} + + AssertionResult::~AssertionResult() {} + + // Result was a success + bool AssertionResult::succeeded() const { + return Catch::isOk( m_resultData.resultType ); + } + + // Result was a success, or failure is suppressed + bool AssertionResult::isOk() const { + return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); + } + + ResultWas::OfType AssertionResult::getResultType() const { + return m_resultData.resultType; + } + + bool AssertionResult::hasExpression() const { + return !m_info.capturedExpression.empty(); + } + + bool AssertionResult::hasMessage() const { + return !m_resultData.message.empty(); + } + + std::string AssertionResult::getExpression() const { + if( isFalseTest( m_info.resultDisposition ) ) + return "!" + m_info.capturedExpression; + else + return m_info.capturedExpression; + } + std::string AssertionResult::getExpressionInMacro() const { + if( m_info.macroName.empty() ) + return m_info.capturedExpression; + else + return m_info.macroName + "( " + m_info.capturedExpression + " )"; + } + + bool AssertionResult::hasExpandedExpression() const { + return hasExpression() && getExpandedExpression() != getExpression(); + } + + std::string AssertionResult::getExpandedExpression() const { + return m_resultData.reconstructedExpression; + } + + std::string AssertionResult::getMessage() const { + return m_resultData.message; + } + SourceLineInfo AssertionResult::getSourceInfo() const { + return m_info.lineInfo; + } + + std::string AssertionResult::getTestMacroName() const { + return m_info.macroName; + } + +} // end namespace Catch + +// #included from: catch_test_case_info.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED + +namespace Catch { + + inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { + if( tag == "." || + tag == "hide" || + tag == "!hide" ) + return TestCaseInfo::IsHidden; + else if( tag == "!throws" ) + return TestCaseInfo::Throws; + else if( tag == "!shouldfail" ) + return TestCaseInfo::ShouldFail; + else if( tag == "!mayfail" ) + return TestCaseInfo::MayFail; + else + return TestCaseInfo::None; + } + inline bool isReservedTag( std::string const& tag ) { + return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] ); + } + inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { + if( isReservedTag( tag ) ) { + { + Colour colourGuard( Colour::Red ); + std::cerr + << "Tag name [" << tag << "] not allowed.\n" + << "Tag names starting with non alpha-numeric characters are reserved\n"; + } + { + Colour colourGuard( Colour::FileName ); + std::cerr << _lineInfo << std::endl; + } + exit(1); + } + } + + TestCase makeTestCase( ITestCase* _testCase, + std::string const& _className, + std::string const& _name, + std::string const& _descOrTags, + SourceLineInfo const& _lineInfo ) + { + bool isHidden( startsWith( _name, "./" ) ); // Legacy support + + // Parse out tags + std::set tags; + std::string desc, tag; + bool inTag = false; + for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { + char c = _descOrTags[i]; + if( !inTag ) { + if( c == '[' ) + inTag = true; + else + desc += c; + } + else { + if( c == ']' ) { + enforceNotReservedTag( tag, _lineInfo ); + + inTag = false; + if( tag == "hide" || tag == "." ) + isHidden = true; + else + tags.insert( tag ); + tag.clear(); + } + else + tag += c; + } + } + if( isHidden ) { + tags.insert( "hide" ); + tags.insert( "." ); + } + + TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); + return TestCase( _testCase, info ); + } + + TestCaseInfo::TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set const& _tags, + SourceLineInfo const& _lineInfo ) + : name( _name ), + className( _className ), + description( _description ), + tags( _tags ), + lineInfo( _lineInfo ), + properties( None ) + { + std::ostringstream oss; + for( std::set::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) { + oss << "[" << *it << "]"; + std::string lcaseTag = toLower( *it ); + properties = static_cast( properties | parseSpecialTag( lcaseTag ) ); + lcaseTags.insert( lcaseTag ); + } + tagsAsString = oss.str(); + } + + TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) + : name( other.name ), + className( other.className ), + description( other.description ), + tags( other.tags ), + lcaseTags( other.lcaseTags ), + tagsAsString( other.tagsAsString ), + lineInfo( other.lineInfo ), + properties( other.properties ) + {} + + bool TestCaseInfo::isHidden() const { + return ( properties & IsHidden ) != 0; + } + bool TestCaseInfo::throws() const { + return ( properties & Throws ) != 0; + } + bool TestCaseInfo::okToFail() const { + return ( properties & (ShouldFail | MayFail ) ) != 0; + } + bool TestCaseInfo::expectedToFail() const { + return ( properties & (ShouldFail ) ) != 0; + } + + TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} + + TestCase::TestCase( TestCase const& other ) + : TestCaseInfo( other ), + test( other.test ) + {} + + TestCase TestCase::withName( std::string const& _newName ) const { + TestCase other( *this ); + other.name = _newName; + return other; + } + + void TestCase::swap( TestCase& other ) { + test.swap( other.test ); + name.swap( other.name ); + className.swap( other.className ); + description.swap( other.description ); + tags.swap( other.tags ); + lcaseTags.swap( other.lcaseTags ); + tagsAsString.swap( other.tagsAsString ); + std::swap( TestCaseInfo::properties, static_cast( other ).properties ); + std::swap( lineInfo, other.lineInfo ); + } + + void TestCase::invoke() const { + test->invoke(); + } + + bool TestCase::operator == ( TestCase const& other ) const { + return test.get() == other.test.get() && + name == other.name && + className == other.className; + } + + bool TestCase::operator < ( TestCase const& other ) const { + return name < other.name; + } + TestCase& TestCase::operator = ( TestCase const& other ) { + TestCase temp( other ); + swap( temp ); + return *this; + } + + TestCaseInfo const& TestCase::getTestCaseInfo() const + { + return *this; + } + +} // end namespace Catch + +// #included from: catch_version.hpp +#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED + +namespace Catch { + + // These numbers are maintained by a script + Version libraryVersion( 1, 0, 53, "master" ); +} + +// #included from: catch_message.hpp +#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED + +namespace Catch { + + MessageInfo::MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + type( _type ), + sequence( ++globalCount ) + {} + + // This may need protecting if threading support is added + unsigned int MessageInfo::globalCount = 0; + + //////////////////////////////////////////////////////////////////////////// + + ScopedMessage::ScopedMessage( MessageBuilder const& builder ) + : m_info( builder.m_info ) + { + m_info.message = builder.m_stream.str(); + getResultCapture().pushScopedMessage( m_info ); + } + ScopedMessage::ScopedMessage( ScopedMessage const& other ) + : m_info( other.m_info ) + {} + + ScopedMessage::~ScopedMessage() { + getResultCapture().popScopedMessage( m_info ); + } + +} // end namespace Catch + +// #included from: catch_legacy_reporter_adapter.hpp +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED + +// #included from: catch_legacy_reporter_adapter.h +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED + +namespace Catch +{ + // Deprecated + struct IReporter : IShared { + virtual ~IReporter(); + + virtual bool shouldRedirectStdout() const = 0; + + virtual void StartTesting() = 0; + virtual void EndTesting( Totals const& totals ) = 0; + virtual void StartGroup( std::string const& groupName ) = 0; + virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; + virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; + virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; + virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; + virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; + virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; + virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; + virtual void Aborted() = 0; + virtual void Result( AssertionResult const& result ) = 0; + }; + + class LegacyReporterAdapter : public SharedImpl + { + public: + LegacyReporterAdapter( Ptr const& legacyReporter ); + virtual ~LegacyReporterAdapter(); + + virtual ReporterPreferences getPreferences() const; + virtual void noMatchingTestCases( std::string const& ); + virtual void testRunStarting( TestRunInfo const& ); + virtual void testGroupStarting( GroupInfo const& groupInfo ); + virtual void testCaseStarting( TestCaseInfo const& testInfo ); + virtual void sectionStarting( SectionInfo const& sectionInfo ); + virtual void assertionStarting( AssertionInfo const& ); + virtual bool assertionEnded( AssertionStats const& assertionStats ); + virtual void sectionEnded( SectionStats const& sectionStats ); + virtual void testCaseEnded( TestCaseStats const& testCaseStats ); + virtual void testGroupEnded( TestGroupStats const& testGroupStats ); + virtual void testRunEnded( TestRunStats const& testRunStats ); + + private: + Ptr m_legacyReporter; + }; +} + +namespace Catch +{ + LegacyReporterAdapter::LegacyReporterAdapter( Ptr const& legacyReporter ) + : m_legacyReporter( legacyReporter ) + {} + LegacyReporterAdapter::~LegacyReporterAdapter() {} + + ReporterPreferences LegacyReporterAdapter::getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); + return prefs; + } + + void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} + void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { + m_legacyReporter->StartTesting(); + } + void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { + m_legacyReporter->StartGroup( groupInfo.name ); + } + void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { + m_legacyReporter->StartTestCase( testInfo ); + } + void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { + m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); + } + void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { + // Not on legacy interface + } + + bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); + rb << it->message; + rb.setResultType( ResultWas::Info ); + AssertionResult result = rb.build(); + m_legacyReporter->Result( result ); + } + } + } + m_legacyReporter->Result( assertionStats.assertionResult ); + return true; + } + void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { + if( sectionStats.missingAssertions ) + m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); + m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); + } + void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { + m_legacyReporter->EndTestCase + ( testCaseStats.testInfo, + testCaseStats.totals, + testCaseStats.stdOut, + testCaseStats.stdErr ); + } + void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { + if( testGroupStats.aborting ) + m_legacyReporter->Aborted(); + m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); + } + void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { + m_legacyReporter->EndTesting( testRunStats.totals ); + } +} + +// #included from: catch_timer.hpp + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#endif + +#ifdef CATCH_PLATFORM_WINDOWS +#include +#else +#include +#endif + +namespace Catch { + + namespace { +#ifdef CATCH_PLATFORM_WINDOWS + uint64_t getCurrentTicks() { + static uint64_t hz=0, hzo=0; + if (!hz) { + QueryPerformanceFrequency((LARGE_INTEGER*)&hz); + QueryPerformanceCounter((LARGE_INTEGER*)&hzo); + } + uint64_t t; + QueryPerformanceCounter((LARGE_INTEGER*)&t); + return ((t-hzo)*1000000)/hz; + } +#else + uint64_t getCurrentTicks() { + timeval t; + gettimeofday(&t,NULL); + return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); + } +#endif + } + + void Timer::start() { + m_ticks = getCurrentTicks(); + } + unsigned int Timer::getElapsedNanoseconds() const { + return static_cast(getCurrentTicks() - m_ticks); + } + unsigned int Timer::getElapsedMilliseconds() const { + return static_cast((getCurrentTicks() - m_ticks)/1000); + } + double Timer::getElapsedSeconds() const { + return (getCurrentTicks() - m_ticks)/1000000.0; + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +// #included from: catch_common.hpp +#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED + +namespace Catch { + + bool startsWith( std::string const& s, std::string const& prefix ) { + return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix; + } + bool endsWith( std::string const& s, std::string const& suffix ) { + return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix; + } + bool contains( std::string const& s, std::string const& infix ) { + return s.find( infix ) != std::string::npos; + } + void toLowerInPlace( std::string& s ) { + std::transform( s.begin(), s.end(), s.begin(), ::tolower ); + } + std::string toLower( std::string const& s ) { + std::string lc = s; + toLowerInPlace( lc ); + return lc; + } + std::string trim( std::string const& str ) { + static char const* whitespaceChars = "\n\r\t "; + std::string::size_type start = str.find_first_not_of( whitespaceChars ); + std::string::size_type end = str.find_last_not_of( whitespaceChars ); + + return start != std::string::npos ? str.substr( start, 1+end-start ) : ""; + } + + pluralise::pluralise( std::size_t count, std::string const& label ) + : m_count( count ), + m_label( label ) + {} + + std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { + os << pluraliser.m_count << " " << pluraliser.m_label; + if( pluraliser.m_count != 1 ) + os << "s"; + return os; + } + + SourceLineInfo::SourceLineInfo() : line( 0 ){} + SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) + : file( _file ), + line( _line ) + {} + SourceLineInfo::SourceLineInfo( SourceLineInfo const& other ) + : file( other.file ), + line( other.line ) + {} + bool SourceLineInfo::empty() const { + return file.empty(); + } + bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { + return line == other.line && file == other.file; + } + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { +#ifndef __GNUG__ + os << info.file << "(" << info.line << ")"; +#else + os << info.file << ":" << info.line; +#endif + return os; + } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { + std::ostringstream oss; + oss << locationInfo << ": Internal Catch error: '" << message << "'"; + if( alwaysTrue() ) + throw std::logic_error( oss.str() ); + } +} + +// #included from: catch_section.hpp +#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED + +namespace Catch { + + SectionInfo::SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description ) + : name( _name ), + description( _description ), + lineInfo( _lineInfo ) + {} + + Section::Section( SectionInfo const& info ) + : m_info( info ), + m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) + { + m_timer.start(); + } + + Section::~Section() { + if( m_sectionIncluded ) + getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() ); + } + + // This indicates whether the section should be executed or not + Section::operator bool() const { + return m_sectionIncluded; + } + +} // end namespace Catch + +// #included from: catch_debugger.hpp +#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED + +#include + +#ifdef CATCH_PLATFORM_MAC + + #include + #include + #include + #include + #include + + namespace Catch{ + + // The following function is taken directly from the following technical note: + // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html + + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + bool isDebuggerActive(){ + + int mib[4]; + struct kinfo_proc info; + size_t size; + + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + + info.kp_proc.p_flag = 0; + + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + // Call sysctl. + + size = sizeof(info); + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0) != 0 ) { + std::cerr << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; + return false; + } + + // We're being debugged if the P_TRACED flag is set. + + return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); + } + } // namespace Catch + +#elif defined(_MSC_VER) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#else + namespace Catch { + inline bool isDebuggerActive() { return false; } + } +#endif // Platform + +#ifdef CATCH_PLATFORM_WINDOWS + extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* ); + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + ::OutputDebugStringA( text.c_str() ); + } + } +#else + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + // !TBD: Need a version for Mac/ XCode and other IDEs + std::cout << text; + } + } +#endif // Platform + +// #included from: catch_tostring.hpp +#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED + +namespace Catch { + +namespace Detail { + + namespace { + struct Endianness { + enum Arch { Big, Little }; + + static Arch which() { + union _{ + int asInt; + char asChar[sizeof (int)]; + } u; + + u.asInt = 1; + return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; + } + }; + } + + std::string rawMemoryToString( const void *object, std::size_t size ) + { + // Reverse order for little endian architectures + int i = 0, end = static_cast( size ), inc = 1; + if( Endianness::which() == Endianness::Little ) { + i = end-1; + end = inc = -1; + } + + unsigned char const *bytes = static_cast(object); + std::ostringstream os; + os << "0x" << std::setfill('0') << std::hex; + for( ; i != end; i += inc ) + os << std::setw(2) << static_cast(bytes[i]); + return os.str(); + } +} + +std::string toString( std::string const& value ) { + std::string s = value; + if( getCurrentContext().getConfig()->showInvisibles() ) { + for(size_t i = 0; i < s.size(); ++i ) { + std::string subs; + switch( s[i] ) { + case '\n': subs = "\\n"; break; + case '\t': subs = "\\t"; break; + default: break; + } + if( !subs.empty() ) { + s = s.substr( 0, i ) + subs + s.substr( i+1 ); + ++i; + } + } + } + return "\"" + s + "\""; +} +std::string toString( std::wstring const& value ) { + + std::string s; + s.reserve( value.size() ); + for(size_t i = 0; i < value.size(); ++i ) + s += value[i] <= 0xff ? static_cast( value[i] ) : '?'; + return toString( s ); +} + +std::string toString( const char* const value ) { + return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); +} + +std::string toString( char* const value ) { + return Catch::toString( static_cast( value ) ); +} + +std::string toString( const wchar_t* const value ) +{ + return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); +} + +std::string toString( wchar_t* const value ) +{ + return Catch::toString( static_cast( value ) ); +} + +std::string toString( int value ) { + std::ostringstream oss; + oss << value; + return oss.str(); +} + +std::string toString( unsigned long value ) { + std::ostringstream oss; + if( value > 8192 ) + oss << "0x" << std::hex << value; + else + oss << value; + return oss.str(); +} + +std::string toString( unsigned int value ) { + return toString( static_cast( value ) ); +} + +template +std::string fpToString( T value, int precision ) { + std::ostringstream oss; + oss << std::setprecision( precision ) + << std::fixed + << value; + std::string d = oss.str(); + std::size_t i = d.find_last_not_of( '0' ); + if( i != std::string::npos && i != d.size()-1 ) { + if( d[i] == '.' ) + i++; + d = d.substr( 0, i+1 ); + } + return d; +} + +std::string toString( const double value ) { + return fpToString( value, 10 ); +} +std::string toString( const float value ) { + return fpToString( value, 5 ) + "f"; +} + +std::string toString( bool value ) { + return value ? "true" : "false"; +} + +std::string toString( char value ) { + return value < ' ' + ? toString( static_cast( value ) ) + : Detail::makeString( value ); +} + +std::string toString( signed char value ) { + return toString( static_cast( value ) ); +} + +std::string toString( unsigned char value ) { + return toString( static_cast( value ) ); +} + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ) { + return "nullptr"; +} +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSObject* const& nsObject ) { + return toString( [nsObject description] ); + } +#endif + +} // end namespace Catch + +// #included from: catch_result_builder.hpp +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED + +namespace Catch { + + ResultBuilder::ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition ) + : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition ), + m_shouldDebugBreak( false ), + m_shouldThrow( false ) + {} + + ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { + m_data.resultType = result; + return *this; + } + ResultBuilder& ResultBuilder::setResultType( bool result ) { + m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; + return *this; + } + ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) { + m_exprComponents.lhs = lhs; + return *this; + } + ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) { + m_exprComponents.rhs = rhs; + return *this; + } + ResultBuilder& ResultBuilder::setOp( std::string const& op ) { + m_exprComponents.op = op; + return *this; + } + + void ResultBuilder::endExpression() { + m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition ); + captureExpression(); + } + + void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { + m_assertionInfo.resultDisposition = resultDisposition; + m_stream.oss << Catch::translateActiveException(); + captureResult( ResultWas::ThrewException ); + } + + void ResultBuilder::captureResult( ResultWas::OfType resultType ) { + setResultType( resultType ); + captureExpression(); + } + + void ResultBuilder::captureExpression() { + AssertionResult result = build(); + getResultCapture().assertionEnded( result ); + + if( !result.isOk() ) { + if( getCurrentContext().getConfig()->shouldDebugBreak() ) + m_shouldDebugBreak = true; + if( getCurrentContext().getRunner()->aborting() || m_assertionInfo.resultDisposition == ResultDisposition::Normal ) + m_shouldThrow = true; + } + } + void ResultBuilder::react() { + if( m_shouldThrow ) + throw Catch::TestFailureException(); + } + + bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } + bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } + + AssertionResult ResultBuilder::build() const + { + assert( m_data.resultType != ResultWas::Unknown ); + + AssertionResultData data = m_data; + + // Flip bool results if testFalse is set + if( m_exprComponents.testFalse ) { + if( data.resultType == ResultWas::Ok ) + data.resultType = ResultWas::ExpressionFailed; + else if( data.resultType == ResultWas::ExpressionFailed ) + data.resultType = ResultWas::Ok; + } + + data.message = m_stream.oss.str(); + data.reconstructedExpression = reconstructExpression(); + if( m_exprComponents.testFalse ) { + if( m_exprComponents.op == "" ) + data.reconstructedExpression = "!" + data.reconstructedExpression; + else + data.reconstructedExpression = "!(" + data.reconstructedExpression + ")"; + } + return AssertionResult( m_assertionInfo, data ); + } + std::string ResultBuilder::reconstructExpression() const { + if( m_exprComponents.op == "" ) + return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs; + else if( m_exprComponents.op == "matches" ) + return m_exprComponents.lhs + " " + m_exprComponents.rhs; + else if( m_exprComponents.op != "!" ) { + if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 && + m_exprComponents.lhs.find("\n") == std::string::npos && + m_exprComponents.rhs.find("\n") == std::string::npos ) + return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs; + else + return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs; + } + else + return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}"; + } + +} // end namespace Catch + +// #included from: catch_tag_alias_registry.hpp +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED + +// #included from: catch_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED + +#include + +namespace Catch { + + class TagAliasRegistry : public ITagAliasRegistry { + public: + virtual ~TagAliasRegistry(); + virtual Option find( std::string const& alias ) const; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; + void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + static TagAliasRegistry& get(); + + private: + std::map m_registry; + }; + +} // end namespace Catch + +#include +#include + +namespace Catch { + + TagAliasRegistry::~TagAliasRegistry() {} + + Option TagAliasRegistry::find( std::string const& alias ) const { + std::map::const_iterator it = m_registry.find( alias ); + if( it != m_registry.end() ) + return it->second; + else + return Option(); + } + + std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { + std::string expandedTestSpec = unexpandedTestSpec; + for( std::map::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); + it != itEnd; + ++it ) { + std::size_t pos = expandedTestSpec.find( it->first ); + if( pos != std::string::npos ) { + expandedTestSpec = expandedTestSpec.substr( 0, pos ) + + it->second.tag + + expandedTestSpec.substr( pos + it->first.size() ); + } + } + return expandedTestSpec; + } + + void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + + if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" already registered.\n" + << "\tFirst seen at " << find(alias)->lineInfo << "\n" + << "\tRedefined at " << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + } + + TagAliasRegistry& TagAliasRegistry::get() { + static TagAliasRegistry instance; + return instance; + + } + + ITagAliasRegistry::~ITagAliasRegistry() {} + ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); } + + RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + try { + TagAliasRegistry::get().add( alias, tag, lineInfo ); + } + catch( std::exception& ex ) { + Colour colourGuard( Colour::Red ); + std::cerr << ex.what() << std::endl; + exit(1); + } + } + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_xml.hpp +#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED + +// #included from: catch_reporter_bases.hpp +#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED + +namespace Catch { + + struct StreamingReporterBase : SharedImpl { + + StreamingReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + {} + + virtual ~StreamingReporterBase(); + + virtual void noMatchingTestCases( std::string const& ) {} + + virtual void testRunStarting( TestRunInfo const& _testRunInfo ) { + currentTestRunInfo = _testRunInfo; + } + virtual void testGroupStarting( GroupInfo const& _groupInfo ) { + currentGroupInfo = _groupInfo; + } + + virtual void testCaseStarting( TestCaseInfo const& _testInfo ) { + currentTestCaseInfo = _testInfo; + } + virtual void sectionStarting( SectionInfo const& _sectionInfo ) { + m_sectionStack.push_back( _sectionInfo ); + } + + virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) { + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) { + currentTestCaseInfo.reset(); + assert( m_sectionStack.empty() ); + } + virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) { + currentGroupInfo.reset(); + } + virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) { + currentTestCaseInfo.reset(); + currentGroupInfo.reset(); + currentTestRunInfo.reset(); + } + + Ptr m_config; + std::ostream& stream; + + LazyStat currentTestRunInfo; + LazyStat currentGroupInfo; + LazyStat currentTestCaseInfo; + + std::vector m_sectionStack; + }; + + struct CumulativeReporterBase : SharedImpl { + template + struct Node : SharedImpl<> { + explicit Node( T const& _value ) : value( _value ) {} + virtual ~Node() {} + + typedef std::vector > ChildNodes; + T value; + ChildNodes children; + }; + struct SectionNode : SharedImpl<> { + explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} + virtual ~SectionNode(); + + bool operator == ( SectionNode const& other ) const { + return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; + } + bool operator == ( Ptr const& other ) const { + return operator==( *other ); + } + + SectionStats stats; + typedef std::vector > ChildSections; + typedef std::vector Assertions; + ChildSections childSections; + Assertions assertions; + std::string stdOut; + std::string stdErr; + }; + + struct BySectionInfo { + BySectionInfo( SectionInfo const& other ) : m_other( other ) {} + BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} + bool operator() ( Ptr const& node ) const { + return node->stats.sectionInfo.lineInfo == m_other.lineInfo; + } + private: + void operator=( BySectionInfo const& ); + SectionInfo const& m_other; + }; + + typedef Node TestCaseNode; + typedef Node TestGroupNode; + typedef Node TestRunNode; + + CumulativeReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + {} + ~CumulativeReporterBase(); + + virtual void testRunStarting( TestRunInfo const& ) {} + virtual void testGroupStarting( GroupInfo const& ) {} + + virtual void testCaseStarting( TestCaseInfo const& ) {} + + virtual void sectionStarting( SectionInfo const& sectionInfo ) { + SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); + Ptr node; + if( m_sectionStack.empty() ) { + if( !m_rootSection ) + m_rootSection = new SectionNode( incompleteStats ); + node = m_rootSection; + } + else { + SectionNode& parentNode = *m_sectionStack.back(); + SectionNode::ChildSections::const_iterator it = + std::find_if( parentNode.childSections.begin(), + parentNode.childSections.end(), + BySectionInfo( sectionInfo ) ); + if( it == parentNode.childSections.end() ) { + node = new SectionNode( incompleteStats ); + parentNode.childSections.push_back( node ); + } + else + node = *it; + } + m_sectionStack.push_back( node ); + m_deepestSection = node; + } + + virtual void assertionStarting( AssertionInfo const& ) {} + + virtual bool assertionEnded( AssertionStats const& assertionStats ) { + assert( !m_sectionStack.empty() ); + SectionNode& sectionNode = *m_sectionStack.back(); + sectionNode.assertions.push_back( assertionStats ); + return true; + } + virtual void sectionEnded( SectionStats const& sectionStats ) { + assert( !m_sectionStack.empty() ); + SectionNode& node = *m_sectionStack.back(); + node.stats = sectionStats; + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + Ptr node = new TestCaseNode( testCaseStats ); + assert( m_sectionStack.size() == 0 ); + node->children.push_back( m_rootSection ); + m_testCases.push_back( node ); + m_rootSection.reset(); + + assert( m_deepestSection ); + m_deepestSection->stdOut = testCaseStats.stdOut; + m_deepestSection->stdErr = testCaseStats.stdErr; + } + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + Ptr node = new TestGroupNode( testGroupStats ); + node->children.swap( m_testCases ); + m_testGroups.push_back( node ); + } + virtual void testRunEnded( TestRunStats const& testRunStats ) { + Ptr node = new TestRunNode( testRunStats ); + node->children.swap( m_testGroups ); + m_testRuns.push_back( node ); + testRunEndedCumulative(); + } + virtual void testRunEndedCumulative() = 0; + + Ptr m_config; + std::ostream& stream; + std::vector m_assertions; + std::vector > > m_sections; + std::vector > m_testCases; + std::vector > m_testGroups; + + std::vector > m_testRuns; + + Ptr m_rootSection; + Ptr m_deepestSection; + std::vector > m_sectionStack; + + }; + +} // end namespace Catch + +// #included from: ../internal/catch_reporter_registrars.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED + +namespace Catch { + + template + class LegacyReporterRegistrar { + + class ReporterFactory : public IReporterFactory { + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new LegacyReporterAdapter( new T( config ) ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + LegacyReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; + + template + class ReporterRegistrar { + + class ReporterFactory : public IReporterFactory { + + // *** Please Note ***: + // - If you end up here looking at a compiler error because it's trying to register + // your custom reporter class be aware that the native reporter interface has changed + // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via + // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. + // However please consider updating to the new interface as the old one is now + // deprecated and will probably be removed quite soon! + // Please contact me via github if you have any questions at all about this. + // In fact, ideally, please contact me anyway to let me know you've hit this - as I have + // no idea who is actually using custom reporters at all (possibly no-one!). + // The new interface is designed to minimise exposure to interface changes in the future. + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + ReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; +} + +#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ + namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } +#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ + namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } + +// #included from: ../internal/catch_xmlwriter.hpp +#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + + class XmlWriter { + public: + + class ScopedElement { + public: + ScopedElement( XmlWriter* writer ) + : m_writer( writer ) + {} + + ScopedElement( ScopedElement const& other ) + : m_writer( other.m_writer ){ + other.m_writer = NULL; + } + + ~ScopedElement() { + if( m_writer ) + m_writer->endElement(); + } + + ScopedElement& writeText( std::string const& text, bool indent = true ) { + m_writer->writeText( text, indent ); + return *this; + } + + template + ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { + m_writer->writeAttribute( name, attribute ); + return *this; + } + + private: + mutable XmlWriter* m_writer; + }; + + XmlWriter() + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &std::cout ) + {} + + XmlWriter( std::ostream& os ) + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &os ) + {} + + ~XmlWriter() { + while( !m_tags.empty() ) + endElement(); + } + +//# ifndef CATCH_CPP11_OR_GREATER +// XmlWriter& operator = ( XmlWriter const& other ) { +// XmlWriter temp( other ); +// swap( temp ); +// return *this; +// } +//# else +// XmlWriter( XmlWriter const& ) = default; +// XmlWriter( XmlWriter && ) = default; +// XmlWriter& operator = ( XmlWriter const& ) = default; +// XmlWriter& operator = ( XmlWriter && ) = default; +//# endif +// +// void swap( XmlWriter& other ) { +// std::swap( m_tagIsOpen, other.m_tagIsOpen ); +// std::swap( m_needsNewline, other.m_needsNewline ); +// std::swap( m_tags, other.m_tags ); +// std::swap( m_indent, other.m_indent ); +// std::swap( m_os, other.m_os ); +// } + + XmlWriter& startElement( std::string const& name ) { + ensureTagClosed(); + newlineIfNecessary(); + stream() << m_indent << "<" << name; + m_tags.push_back( name ); + m_indent += " "; + m_tagIsOpen = true; + return *this; + } + + ScopedElement scopedElement( std::string const& name ) { + ScopedElement scoped( this ); + startElement( name ); + return scoped; + } + + XmlWriter& endElement() { + newlineIfNecessary(); + m_indent = m_indent.substr( 0, m_indent.size()-2 ); + if( m_tagIsOpen ) { + stream() << "/>\n"; + m_tagIsOpen = false; + } + else { + stream() << m_indent << "\n"; + } + m_tags.pop_back(); + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { + if( !name.empty() && !attribute.empty() ) { + stream() << " " << name << "=\""; + writeEncodedText( attribute ); + stream() << "\""; + } + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, bool attribute ) { + stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\""; + return *this; + } + + template + XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { + if( !name.empty() ) + stream() << " " << name << "=\"" << attribute << "\""; + return *this; + } + + XmlWriter& writeText( std::string const& text, bool indent = true ) { + if( !text.empty() ){ + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if( tagWasOpen && indent ) + stream() << m_indent; + writeEncodedText( text ); + m_needsNewline = true; + } + return *this; + } + + XmlWriter& writeComment( std::string const& text ) { + ensureTagClosed(); + stream() << m_indent << ""; + m_needsNewline = true; + return *this; + } + + XmlWriter& writeBlankLine() { + ensureTagClosed(); + stream() << "\n"; + return *this; + } + + void setStream( std::ostream& os ) { + m_os = &os; + } + + private: + XmlWriter( XmlWriter const& ); + void operator=( XmlWriter const& ); + + std::ostream& stream() { + return *m_os; + } + + void ensureTagClosed() { + if( m_tagIsOpen ) { + stream() << ">\n"; + m_tagIsOpen = false; + } + } + + void newlineIfNecessary() { + if( m_needsNewline ) { + stream() << "\n"; + m_needsNewline = false; + } + } + + void writeEncodedText( std::string const& text ) { + static const char* charsToEncode = "<&\""; + std::string mtext = text; + std::string::size_type pos = mtext.find_first_of( charsToEncode ); + while( pos != std::string::npos ) { + stream() << mtext.substr( 0, pos ); + + switch( mtext[pos] ) { + case '<': + stream() << "<"; + break; + case '&': + stream() << "&"; + break; + case '\"': + stream() << """; + break; + } + mtext = mtext.substr( pos+1 ); + pos = mtext.find_first_of( charsToEncode ); + } + stream() << mtext; + } + + bool m_tagIsOpen; + bool m_needsNewline; + std::vector m_tags; + std::string m_indent; + std::ostream* m_os; + }; + +} +namespace Catch { + class XmlReporter : public SharedImpl { + public: + XmlReporter( ReporterConfig const& config ) : m_config( config ), m_sectionDepth( 0 ) {} + + static std::string getDescription() { + return "Reports test results as an XML document"; + } + virtual ~XmlReporter(); + + private: // IReporter + + virtual bool shouldRedirectStdout() const { + return true; + } + + virtual void StartTesting() { + m_xml.setStream( m_config.stream() ); + m_xml.startElement( "Catch" ); + if( !m_config.fullConfig()->name().empty() ) + m_xml.writeAttribute( "name", m_config.fullConfig()->name() ); + } + + virtual void EndTesting( const Totals& totals ) { + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", totals.assertions.passed ) + .writeAttribute( "failures", totals.assertions.failed ) + .writeAttribute( "expectedFailures", totals.assertions.failedButOk ); + m_xml.endElement(); + } + + virtual void StartGroup( const std::string& groupName ) { + m_xml.startElement( "Group" ) + .writeAttribute( "name", groupName ); + } + + virtual void EndGroup( const std::string&, const Totals& totals ) { + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", totals.assertions.passed ) + .writeAttribute( "failures", totals.assertions.failed ) + .writeAttribute( "expectedFailures", totals.assertions.failedButOk ); + m_xml.endElement(); + } + + virtual void StartSection( const std::string& sectionName, const std::string& description ) { + if( m_sectionDepth++ > 0 ) { + m_xml.startElement( "Section" ) + .writeAttribute( "name", trim( sectionName ) ) + .writeAttribute( "description", description ); + } + } + virtual void NoAssertionsInSection( const std::string& ) {} + virtual void NoAssertionsInTestCase( const std::string& ) {} + + virtual void EndSection( const std::string& /*sectionName*/, const Counts& assertions ) { + if( --m_sectionDepth > 0 ) { + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", assertions.passed ) + .writeAttribute( "failures", assertions.failed ) + .writeAttribute( "expectedFailures", assertions.failedButOk ); + m_xml.endElement(); + } + } + + virtual void StartTestCase( const Catch::TestCaseInfo& testInfo ) { + m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); + m_currentTestSuccess = true; + } + + virtual void Result( const Catch::AssertionResult& assertionResult ) { + if( !m_config.fullConfig()->includeSuccessfulResults() && assertionResult.getResultType() == ResultWas::Ok ) + return; + + if( assertionResult.hasExpression() ) { + m_xml.startElement( "Expression" ) + .writeAttribute( "success", assertionResult.succeeded() ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ); + + m_xml.scopedElement( "Original" ) + .writeText( assertionResult.getExpression() ); + m_xml.scopedElement( "Expanded" ) + .writeText( assertionResult.getExpandedExpression() ); + m_currentTestSuccess &= assertionResult.succeeded(); + } + + switch( assertionResult.getResultType() ) { + case ResultWas::ThrewException: + m_xml.scopedElement( "Exception" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + m_currentTestSuccess = false; + break; + case ResultWas::Info: + m_xml.scopedElement( "Info" ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Warning: + m_xml.scopedElement( "Warning" ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::ExplicitFailure: + m_xml.scopedElement( "Failure" ) + .writeText( assertionResult.getMessage() ); + m_currentTestSuccess = false; + break; + case ResultWas::Unknown: + case ResultWas::Ok: + case ResultWas::FailureBit: + case ResultWas::ExpressionFailed: + case ResultWas::Exception: + case ResultWas::DidntThrowException: + break; + } + if( assertionResult.hasExpression() ) + m_xml.endElement(); + } + + virtual void Aborted() { + // !TBD + } + + virtual void EndTestCase( const Catch::TestCaseInfo&, const Totals&, const std::string&, const std::string& ) { + m_xml.scopedElement( "OverallResult" ).writeAttribute( "success", m_currentTestSuccess ); + m_xml.endElement(); + } + + private: + ReporterConfig m_config; + bool m_currentTestSuccess; + XmlWriter m_xml; + int m_sectionDepth; + }; + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_junit.hpp +#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED + +#include + +namespace Catch { + + class JunitReporter : public CumulativeReporterBase { + public: + JunitReporter( ReporterConfig const& _config ) + : CumulativeReporterBase( _config ), + xml( _config.stream() ) + {} + + ~JunitReporter(); + + static std::string getDescription() { + return "Reports test results in an XML format that looks like Ant's junitreport target"; + } + + virtual void noMatchingTestCases( std::string const& /*spec*/ ) {} + + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = true; + return prefs; + } + + virtual void testRunStarting( TestRunInfo const& runInfo ) { + CumulativeReporterBase::testRunStarting( runInfo ); + xml.startElement( "testsuites" ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) { + suiteTimer.start(); + stdOutForSuite.str(""); + stdErrForSuite.str(""); + unexpectedExceptions = 0; + CumulativeReporterBase::testGroupStarting( groupInfo ); + } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) + unexpectedExceptions++; + return CumulativeReporterBase::assertionEnded( assertionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + stdOutForSuite << testCaseStats.stdOut; + stdErrForSuite << testCaseStats.stdErr; + CumulativeReporterBase::testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + double suiteTime = suiteTimer.getElapsedSeconds(); + CumulativeReporterBase::testGroupEnded( testGroupStats ); + writeGroup( *m_testGroups.back(), suiteTime ); + } + + virtual void testRunEndedCumulative() { + xml.endElement(); + } + + void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); + TestGroupStats const& stats = groupNode.value; + xml.writeAttribute( "name", stats.groupInfo.name ); + xml.writeAttribute( "errors", unexpectedExceptions ); + xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); + xml.writeAttribute( "tests", stats.totals.assertions.total() ); + xml.writeAttribute( "hostname", "tbd" ); // !TBD + if( m_config->showDurations() == ShowDurations::Never ) + xml.writeAttribute( "time", "" ); + else + xml.writeAttribute( "time", suiteTime ); + xml.writeAttribute( "timestamp", "tbd" ); // !TBD + + // Write test cases + for( TestGroupNode::ChildNodes::const_iterator + it = groupNode.children.begin(), itEnd = groupNode.children.end(); + it != itEnd; + ++it ) + writeTestCase( **it ); + + xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); + xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); + } + + void writeTestCase( TestCaseNode const& testCaseNode ) { + TestCaseStats const& stats = testCaseNode.value; + + // All test cases have exactly one section - which represents the + // test case itself. That section may have 0-n nested sections + assert( testCaseNode.children.size() == 1 ); + SectionNode const& rootSection = *testCaseNode.children.front(); + + std::string className = stats.testInfo.className; + + if( className.empty() ) { + if( rootSection.childSections.empty() ) + className = "global"; + } + writeSection( className, "", rootSection ); + } + + void writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode ) { + std::string name = trim( sectionNode.stats.sectionInfo.name ); + if( !rootName.empty() ) + name = rootName + "/" + name; + + if( !sectionNode.assertions.empty() || + !sectionNode.stdOut.empty() || + !sectionNode.stdErr.empty() ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); + if( className.empty() ) { + xml.writeAttribute( "classname", name ); + xml.writeAttribute( "name", "root" ); + } + else { + xml.writeAttribute( "classname", className ); + xml.writeAttribute( "name", name ); + } + xml.writeAttribute( "time", toString( sectionNode.stats.durationInSeconds ) ); + + writeAssertions( sectionNode ); + + if( !sectionNode.stdOut.empty() ) + xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); + if( !sectionNode.stdErr.empty() ) + xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); + } + for( SectionNode::ChildSections::const_iterator + it = sectionNode.childSections.begin(), + itEnd = sectionNode.childSections.end(); + it != itEnd; + ++it ) + if( className.empty() ) + writeSection( name, "", **it ); + else + writeSection( className, name, **it ); + } + + void writeAssertions( SectionNode const& sectionNode ) { + for( SectionNode::Assertions::const_iterator + it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); + it != itEnd; + ++it ) + writeAssertion( *it ); + } + void writeAssertion( AssertionStats const& stats ) { + AssertionResult const& result = stats.assertionResult; + if( !result.isOk() ) { + std::string elementName; + switch( result.getResultType() ) { + case ResultWas::ThrewException: + elementName = "error"; + break; + case ResultWas::ExplicitFailure: + elementName = "failure"; + break; + case ResultWas::ExpressionFailed: + elementName = "failure"; + break; + case ResultWas::DidntThrowException: + elementName = "failure"; + break; + + // We should never see these here: + case ResultWas::Info: + case ResultWas::Warning: + case ResultWas::Ok: + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + elementName = "internalError"; + break; + } + + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); + + xml.writeAttribute( "message", result.getExpandedExpression() ); + xml.writeAttribute( "type", result.getTestMacroName() ); + + std::ostringstream oss; + if( !result.getMessage().empty() ) + oss << result.getMessage() << "\n"; + for( std::vector::const_iterator + it = stats.infoMessages.begin(), + itEnd = stats.infoMessages.end(); + it != itEnd; + ++it ) + if( it->type == ResultWas::Info ) + oss << it->message << "\n"; + + oss << "at " << result.getSourceInfo(); + xml.writeText( oss.str(), false ); + } + } + + XmlWriter xml; + Timer suiteTimer; + std::ostringstream stdOutForSuite; + std::ostringstream stdErrForSuite; + unsigned int unexpectedExceptions; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_console.hpp +#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED + +#include + +namespace Catch { + + struct ConsoleReporter : StreamingReporterBase { + ConsoleReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_headerPrinted( false ) + {} + + virtual ~ConsoleReporter(); + static std::string getDescription() { + return "Reports test results as plain lines of text"; + } + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = false; + return prefs; + } + + virtual void noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + lazyPrint(); + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + stream << std::endl; + return true; + } + + virtual void sectionStarting( SectionInfo const& _sectionInfo ) { + m_headerPrinted = false; + StreamingReporterBase::sectionStarting( _sectionInfo ); + } + virtual void sectionEnded( SectionStats const& _sectionStats ) { + if( _sectionStats.missingAssertions ) { + lazyPrint(); + Colour colour( Colour::ResultError ); + if( m_sectionStack.size() > 1 ) + stream << "\nNo assertions in section"; + else + stream << "\nNo assertions in test case"; + stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; + } + if( m_headerPrinted ) { + if( m_config->showDurations() == ShowDurations::Always ) + stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + m_headerPrinted = false; + } + else { + if( m_config->showDurations() == ShowDurations::Always ) + stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + } + StreamingReporterBase::sectionEnded( _sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) { + StreamingReporterBase::testCaseEnded( _testCaseStats ); + m_headerPrinted = false; + } + virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) { + if( currentGroupInfo.used ) { + printSummaryDivider(); + stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; + printTotals( _testGroupStats.totals ); + stream << "\n" << std::endl; + } + StreamingReporterBase::testGroupEnded( _testGroupStats ); + } + virtual void testRunEnded( TestRunStats const& _testRunStats ) { + printTotalsDivider( _testRunStats.totals ); + printTotals( _testRunStats.totals ); + stream << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ), + stats( _stats ), + result( _stats.assertionResult ), + colour( Colour::None ), + message( result.getMessage() ), + messages( _stats.infoMessages ), + printInfoMessages( _printInfoMessages ) + { + switch( result.getResultType() ) { + case ResultWas::Ok: + colour = Colour::Success; + passOrFail = "PASSED"; + //if( result.hasMessage() ) + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) { + colour = Colour::Success; + passOrFail = "FAILED - but was ok"; + } + else { + colour = Colour::Error; + passOrFail = "FAILED"; + } + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ThrewException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to unexpected exception with message"; + break; + case ResultWas::DidntThrowException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "because no exception was thrown where one was expected"; + break; + case ResultWas::Info: + messageLabel = "info"; + break; + case ResultWas::Warning: + messageLabel = "warning"; + break; + case ResultWas::ExplicitFailure: + passOrFail = "FAILED"; + colour = Colour::Error; + if( _stats.infoMessages.size() == 1 ) + messageLabel = "explicitly with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "explicitly with messages"; + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + passOrFail = "** internal error **"; + colour = Colour::Error; + break; + } + } + + void print() const { + printSourceInfo(); + if( stats.totals.assertions.total() > 0 ) { + if( result.isOk() ) + stream << "\n"; + printResultType(); + printOriginalExpression(); + printReconstructedExpression(); + } + else { + stream << "\n"; + } + printMessage(); + } + + private: + void printResultType() const { + if( !passOrFail.empty() ) { + Colour colourGuard( colour ); + stream << passOrFail << ":\n"; + } + } + void printOriginalExpression() const { + if( result.hasExpression() ) { + Colour colourGuard( Colour::OriginalExpression ); + stream << " "; + stream << result.getExpressionInMacro(); + stream << "\n"; + } + } + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + stream << "with expansion:\n"; + Colour colourGuard( Colour::ReconstructedExpression ); + stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n"; + } + } + void printMessage() const { + if( !messageLabel.empty() ) + stream << messageLabel << ":" << "\n"; + for( std::vector::const_iterator it = messages.begin(), itEnd = messages.end(); + it != itEnd; + ++it ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || it->type != ResultWas::Info ) + stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n"; + } + } + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ": "; + } + + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + Colour::Code colour; + std::string passOrFail; + std::string messageLabel; + std::string message; + std::vector messages; + bool printInfoMessages; + }; + + void lazyPrint() { + + if( !currentTestRunInfo.used ) + lazyPrintRunInfo(); + if( !currentGroupInfo.used ) + lazyPrintGroupInfo(); + + if( !m_headerPrinted ) { + printTestCaseAndSectionHeader(); + m_headerPrinted = true; + } + } + void lazyPrintRunInfo() { + stream << "\n" << getLineOfChars<'~'>() << "\n"; + Colour colour( Colour::SecondaryText ); + stream << currentTestRunInfo->name + << " is a Catch v" << libraryVersion.majorVersion << "." + << libraryVersion.minorVersion << " b" + << libraryVersion.buildNumber; + if( libraryVersion.branchName != std::string( "master" ) ) + stream << " (" << libraryVersion.branchName << ")"; + stream << " host application.\n" + << "Run with -? for options\n\n"; + + currentTestRunInfo.used = true; + } + void lazyPrintGroupInfo() { + if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { + printClosedHeader( "Group: " + currentGroupInfo->name ); + currentGroupInfo.used = true; + } + } + void printTestCaseAndSectionHeader() { + assert( !m_sectionStack.empty() ); + printOpenHeader( currentTestCaseInfo->name ); + + if( m_sectionStack.size() > 1 ) { + Colour colourGuard( Colour::Headers ); + + std::vector::const_iterator + it = m_sectionStack.begin()+1, // Skip first section (test case) + itEnd = m_sectionStack.end(); + for( ; it != itEnd; ++it ) + printHeaderString( it->name, 2 ); + } + + SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; + + if( !lineInfo.empty() ){ + stream << getLineOfChars<'-'>() << "\n"; + Colour colourGuard( Colour::FileName ); + stream << lineInfo << "\n"; + } + stream << getLineOfChars<'.'>() << "\n" << std::endl; + } + + void printClosedHeader( std::string const& _name ) { + printOpenHeader( _name ); + stream << getLineOfChars<'.'>() << "\n"; + } + void printOpenHeader( std::string const& _name ) { + stream << getLineOfChars<'-'>() << "\n"; + { + Colour colourGuard( Colour::Headers ); + printHeaderString( _name ); + } + } + + // if string has a : in first line will set indent to follow it on + // subsequent lines + void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { + std::size_t i = _string.find( ": " ); + if( i != std::string::npos ) + i+=2; + else + i = 0; + stream << Text( _string, TextAttributes() + .setIndent( indent+i) + .setInitialIndent( indent ) ) << "\n"; + } + + struct SummaryColumn { + + SummaryColumn( std::string const& _label, Colour::Code _colour ) + : label( _label ), + colour( _colour ) + {} + SummaryColumn addRow( std::size_t count ) { + std::ostringstream oss; + oss << count; + std::string row = oss.str(); + for( std::vector::iterator it = rows.begin(); it != rows.end(); ++it ) { + while( it->size() < row.size() ) + *it = " " + *it; + while( it->size() > row.size() ) + row = " " + row; + } + rows.push_back( row ); + return *this; + } + + std::string label; + Colour::Code colour; + std::vector rows; + + }; + + void printTotals( Totals const& totals ) { + if( totals.testCases.total() == 0 ) { + stream << Colour( Colour::Warning ) << "No tests ran\n"; + } + else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) { + stream << Colour( Colour::ResultSuccess ) << "All tests passed"; + stream << " (" + << pluralise( totals.assertions.passed, "assertion" ) << " in " + << pluralise( totals.testCases.passed, "test case" ) << ")" + << "\n"; + } + else { + + std::vector columns; + columns.push_back( SummaryColumn( "", Colour::None ) + .addRow( totals.testCases.total() ) + .addRow( totals.assertions.total() ) ); + columns.push_back( SummaryColumn( "passed", Colour::Success ) + .addRow( totals.testCases.passed ) + .addRow( totals.assertions.passed ) ); + columns.push_back( SummaryColumn( "failed", Colour::ResultError ) + .addRow( totals.testCases.failed ) + .addRow( totals.assertions.failed ) ); + columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) + .addRow( totals.testCases.failedButOk ) + .addRow( totals.assertions.failedButOk ) ); + + printSummaryRow( "test cases", columns, 0 ); + printSummaryRow( "assertions", columns, 1 ); + } + } + void printSummaryRow( std::string const& label, std::vector const& cols, std::size_t row ) { + for( std::vector::const_iterator it = cols.begin(); it != cols.end(); ++it ) { + std::string value = it->rows[row]; + if( it->label.empty() ) { + stream << label << ": "; + if( value != "0" ) + stream << value; + else + stream << Colour( Colour::Warning ) << "- none -"; + } + else if( value != "0" ) { + stream << Colour( Colour::LightGrey ) << " | "; + stream << Colour( it->colour ) + << value << " " << it->label; + } + } + stream << "\n"; + } + + static std::size_t makeRatio( std::size_t number, std::size_t total ) { + std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; + return ( ratio == 0 && number > 0 ) ? 1 : ratio; + } + static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { + if( i > j && i > k ) + return i; + else if( j > k ) + return j; + else + return k; + } + + void printTotalsDivider( Totals const& totals ) { + if( totals.testCases.total() > 0 ) { + std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); + std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); + std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); + while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )++; + while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )--; + + stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); + stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); + if( totals.testCases.allPassed() ) + stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); + else + stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); + } + else { + stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); + } + stream << "\n"; + } + void printSummaryDivider() { + stream << getLineOfChars<'-'>() << "\n"; + } + template + static char const* getLineOfChars() { + static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; + if( !*line ) { + memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); + line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; + } + return line; + } + + private: + bool m_headerPrinted; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_compact.hpp +#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED + +namespace Catch { + + struct CompactReporter : StreamingReporterBase { + + CompactReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual ~CompactReporter(); + + static std::string getDescription() { + return "Reports test results on a single line, suitable for IDEs"; + } + + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = false; + return prefs; + } + + virtual void noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + + stream << std::endl; + return true; + } + + virtual void testRunEnded( TestRunStats const& _testRunStats ) { + printTotals( _testRunStats.totals ); + stream << "\n" << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ) + , stats( _stats ) + , result( _stats.assertionResult ) + , messages( _stats.infoMessages ) + , itMessage( _stats.infoMessages.begin() ) + , printInfoMessages( _printInfoMessages ) + {} + + void print() { + printSourceInfo(); + + itMessage = messages.begin(); + + switch( result.getResultType() ) { + case ResultWas::Ok: + printResultType( Colour::ResultSuccess, passedString() ); + printOriginalExpression(); + printReconstructedExpression(); + if ( ! result.hasExpression() ) + printRemainingMessages( Colour::None ); + else + printRemainingMessages(); + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) + printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); + else + printResultType( Colour::Error, failedString() ); + printOriginalExpression(); + printReconstructedExpression(); + printRemainingMessages(); + break; + case ResultWas::ThrewException: + printResultType( Colour::Error, failedString() ); + printIssue( "unexpected exception with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::DidntThrowException: + printResultType( Colour::Error, failedString() ); + printIssue( "expected exception, got none" ); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::Info: + printResultType( Colour::None, "info" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::Warning: + printResultType( Colour::None, "warning" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::ExplicitFailure: + printResultType( Colour::Error, failedString() ); + printIssue( "explicitly" ); + printRemainingMessages( Colour::None ); + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + printResultType( Colour::Error, "** internal error **" ); + break; + } + } + + private: + // Colour::LightGrey + + static Colour::Code dimColour() { return Colour::FileName; } + +#ifdef CATCH_PLATFORM_MAC + static const char* failedString() { return "FAILED"; } + static const char* passedString() { return "PASSED"; } +#else + static const char* failedString() { return "failed"; } + static const char* passedString() { return "passed"; } +#endif + + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ":"; + } + + void printResultType( Colour::Code colour, std::string passOrFail ) const { + if( !passOrFail.empty() ) { + { + Colour colourGuard( colour ); + stream << " " << passOrFail; + } + stream << ":"; + } + } + + void printIssue( std::string issue ) const { + stream << " " << issue; + } + + void printExpressionWas() { + if( result.hasExpression() ) { + stream << ";"; + { + Colour colour( dimColour() ); + stream << " expression was:"; + } + printOriginalExpression(); + } + } + + void printOriginalExpression() const { + if( result.hasExpression() ) { + stream << " " << result.getExpression(); + } + } + + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + { + Colour colour( dimColour() ); + stream << " for: "; + } + stream << result.getExpandedExpression(); + } + } + + void printMessage() { + if ( itMessage != messages.end() ) { + stream << " '" << itMessage->message << "'"; + ++itMessage; + } + } + + void printRemainingMessages( Colour::Code colour = dimColour() ) { + if ( itMessage == messages.end() ) + return; + + // using messages.end() directly yields compilation error: + std::vector::const_iterator itEnd = messages.end(); + const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); + + { + Colour colourGuard( colour ); + stream << " with " << pluralise( N, "message" ) << ":"; + } + + for(; itMessage != itEnd; ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || itMessage->type != ResultWas::Info ) { + stream << " '" << itMessage->message << "'"; + if ( ++itMessage != itEnd ) { + Colour colourGuard( dimColour() ); + stream << " and"; + } + } + } + } + + private: + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + std::vector messages; + std::vector::const_iterator itMessage; + bool printInfoMessages; + }; + + // Colour, message variants: + // - white: No tests ran. + // - red: Failed [both/all] N test cases, failed [both/all] M assertions. + // - white: Passed [both/all] N test cases (no assertions). + // - red: Failed N tests cases, failed M assertions. + // - green: Passed [both/all] N tests cases with M assertions. + + std::string bothOrAll( std::size_t count ) const { + return count == 1 ? "" : count == 2 ? "both " : "all " ; + } + + void printTotals( const Totals& totals ) const { + if( totals.testCases.total() == 0 ) { + stream << "No tests ran."; + } + else if( totals.testCases.failed == totals.testCases.total() ) { + Colour colour( Colour::ResultError ); + const std::string qualify_assertions_failed = + totals.assertions.failed == totals.assertions.total() ? + bothOrAll( totals.assertions.failed ) : ""; + stream << + "Failed " << bothOrAll( totals.testCases.failed ) + << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << qualify_assertions_failed << + pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else if( totals.assertions.total() == 0 ) { + stream << + "Passed " << bothOrAll( totals.testCases.total() ) + << pluralise( totals.testCases.total(), "test case" ) + << " (no assertions)."; + } + else if( totals.assertions.failed ) { + Colour colour( Colour::ResultError ); + stream << + "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else { + Colour colour( Colour::ResultSuccess ); + stream << + "Passed " << bothOrAll( totals.testCases.passed ) + << pluralise( totals.testCases.passed, "test case" ) << + " with " << pluralise( totals.assertions.passed, "assertion" ) << "."; + } + } + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) + +} // end namespace Catch + +namespace Catch { + NonCopyable::~NonCopyable() {} + IShared::~IShared() {} + StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} + IContext::~IContext() {} + IResultCapture::~IResultCapture() {} + ITestCase::~ITestCase() {} + ITestCaseRegistry::~ITestCaseRegistry() {} + IRegistryHub::~IRegistryHub() {} + IMutableRegistryHub::~IMutableRegistryHub() {} + IExceptionTranslator::~IExceptionTranslator() {} + IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} + IReporter::~IReporter() {} + IReporterFactory::~IReporterFactory() {} + IReporterRegistry::~IReporterRegistry() {} + IStreamingReporter::~IStreamingReporter() {} + AssertionStats::~AssertionStats() {} + SectionStats::~SectionStats() {} + TestCaseStats::~TestCaseStats() {} + TestGroupStats::~TestGroupStats() {} + TestRunStats::~TestRunStats() {} + CumulativeReporterBase::SectionNode::~SectionNode() {} + CumulativeReporterBase::~CumulativeReporterBase() {} + + StreamingReporterBase::~StreamingReporterBase() {} + ConsoleReporter::~ConsoleReporter() {} + CompactReporter::~CompactReporter() {} + IRunner::~IRunner() {} + IMutableContext::~IMutableContext() {} + IConfig::~IConfig() {} + XmlReporter::~XmlReporter() {} + JunitReporter::~JunitReporter() {} + TestRegistry::~TestRegistry() {} + FreeFunctionTestCase::~FreeFunctionTestCase() {} + IGeneratorInfo::~IGeneratorInfo() {} + IGeneratorsForTest::~IGeneratorsForTest() {} + TestSpec::Pattern::~Pattern() {} + TestSpec::NamePattern::~NamePattern() {} + TestSpec::TagPattern::~TagPattern() {} + TestSpec::ExcludedPattern::~ExcludedPattern() {} + + Matchers::Impl::StdString::Equals::~Equals() {} + Matchers::Impl::StdString::Contains::~Contains() {} + Matchers::Impl::StdString::StartsWith::~StartsWith() {} + Matchers::Impl::StdString::EndsWith::~EndsWith() {} + + void Config::dummy() {} + + INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( "xml", XmlReporter ) +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif + +#ifdef CATCH_CONFIG_MAIN +// #included from: internal/catch_default_main.hpp +#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED + +#ifndef __OBJC__ + +// Standard C/C++ main entry point +int main (int argc, char * const argv[]) { + return Catch::Session().run( argc, argv ); +} + +#else // __OBJC__ + +// Objective-C entry point +int main (int argc, char * const argv[]) { +#if !CATCH_ARC_ENABLED + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; +#endif + + Catch::registerTestMethods(); + int result = Catch::Session().run( argc, (char* const*)argv ); + +#if !CATCH_ARC_ENABLED + [pool drain]; +#endif + + return result; +} + +#endif // __OBJC__ + +#endif + +#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED +# undef CLARA_CONFIG_MAIN +#endif + +////// + +// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ +#ifdef CATCH_CONFIG_PREFIX_ALL + +#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) +#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) + +#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS" ) +#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) +#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) + +#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) +#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" ) +#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" ) +#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" ) +#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" ) + +#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) +#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) +#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) +#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" ) + +#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg ) +#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) +#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) + #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) +#else + #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) + #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) +#endif +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) +#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define CATCH_GIVEN( desc ) CATCH_SECTION( "Given: " desc, "" ) +#define CATCH_WHEN( desc ) CATCH_SECTION( " When: " desc, "" ) +#define CATCH_AND_WHEN( desc ) CATCH_SECTION( " And: " desc, "" ) +#define CATCH_THEN( desc ) CATCH_SECTION( " Then: " desc, "" ) +#define CATCH_AND_THEN( desc ) CATCH_SECTION( " And: " desc, "" ) + +// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required +#else + +#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) +#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) + +#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "REQUIRE_THROWS" ) +#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) +#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) + +#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) +#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" ) +#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" ) +#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) +#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) + +#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS" ) +#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) +#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) +#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" ) + +#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg ) +#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) +#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) + #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) +#else + #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) + #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) +#endif +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +#endif + +#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) +#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define GIVEN( desc ) SECTION( " Given: " desc, "" ) +#define WHEN( desc ) SECTION( " When: " desc, "" ) +#define AND_WHEN( desc ) SECTION( "And when: " desc, "" ) +#define THEN( desc ) SECTION( " Then: " desc, "" ) +#define AND_THEN( desc ) SECTION( " And: " desc, "" ) + +using Catch::Detail::Approx; + +// #included from: internal/catch_reenable_warnings.h + +#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic pop +#elif defined __GNUC__ +#pragma GCC diagnostic pop +#endif + +#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + From e02a28aab85d95604525752de03383355367ba04 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 13 Nov 2014 09:12:41 -0500 Subject: [PATCH 0549/1866] Adds catch test for range *makefile to be replaced --- catchtest/Makefile | 13 ++++ catchtest/run_test_range.cpp | 2 + catchtest/test_range.cpp | 140 +++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 catchtest/Makefile create mode 100644 catchtest/run_test_range.cpp create mode 100644 catchtest/test_range.cpp diff --git a/catchtest/Makefile b/catchtest/Makefile new file mode 100644 index 00000000..c3ba6c57 --- /dev/null +++ b/catchtest/Makefile @@ -0,0 +1,13 @@ +CXX = g++ +CXXFLAGS = -Wall -Wextra -pedantic -std=c++11 +CPPFLAGS = -I.. +LINK.o = $(CXX) + +all: test_range + +test_range: test_range.o run_test_range.o + +test_range.o: test_range.cpp + +clean: + rm -f test_range *.o diff --git a/catchtest/run_test_range.cpp b/catchtest/run_test_range.cpp new file mode 100644 index 00000000..0c7c351f --- /dev/null +++ b/catchtest/run_test_range.cpp @@ -0,0 +1,2 @@ +#define CATCH_CONFIG_MAIN +#include "catch.hpp" diff --git a/catchtest/test_range.cpp b/catchtest/test_range.cpp new file mode 100644 index 00000000..7c853595 --- /dev/null +++ b/catchtest/test_range.cpp @@ -0,0 +1,140 @@ +#include "range.hpp" + +#include +#include +#include + +#include "catch.hpp" + +using Vec = const std::vector; +using iter::range; + + +TEST_CASE("Range works with only stop", "[range]") { + auto r = range(5); + Vec v(std::begin(r), std::end(r)); + Vec vc{0, 1, 2, 3, 4}; + + REQUIRE( v == vc ); +} + +TEST_CASE("Range works with start and stop", "[range]") { + auto r = range(1, 5); + Vec v(std::begin(r), std::end(r)); + Vec vc {1, 2, 3, 4}; + + REQUIRE( v == vc ); +} + +TEST_CASE("Range works with positive step > 1", "[range]") { + auto r = range(1, 10, 3); + Vec v(std::begin(r), std::end(r)); + Vec vc{1, 4, 7}; + + REQUIRE( v == vc ); +} + +TEST_CASE("range(0) is empty", "[range]") { + auto r = iter::range(0); + Vec v(std::begin(r), std::end(r)); + REQUIRE( v.empty() ); +} + +TEST_CASE("start > stop produces empty range", "[range]") { + auto r = range(5, 0); + Vec v(std::begin(r), std::end(r)); + REQUIRE( v.empty() ); +} + +TEST_CASE("start < stop and step < 0 produces empty range", "[range]") { + auto r = range(0, 5, -1); + Vec v(std::begin(r), std::end(r)); + REQUIRE( v.empty() ); +} + +TEST_CASE("Range with only a negative stop is empty", "[range]") { + auto r = range(-3); + Vec v(std::begin(r), std::end(r)); + + REQUIRE( v.empty() ); +} + +TEST_CASE("Range works with negative step", "[range]") { + auto r = range(5, -5, -3); + Vec v(std::begin(r), std::end(r)); + Vec vc{5, 2, -1, -4}; + + REQUIRE( v == vc ); +} + +TEST_CASE("Range stops short when step doesn't divide stop-start", "[range]") { + auto r = range(0, 5, 2); + Vec v(std::begin(r), std::end(r)); + Vec vc{0, 2, 4}; + + REQUIRE( v == vc ); + +} + +TEST_CASE("Range stops short when step > stop-start", "[range]") { + auto r = range(0, 10, 20); + Vec v(std::begin(r), std::end(r)); + REQUIRE( v.size() == 1 ); +} + +TEST_CASE("No 0 step ranges allowed", "[range]") { + REQUIRE_THROWS(range(0, 1, 0)); +} + +TEST_CASE("Range works with a variable start, stop, and step", "[range]") { + constexpr int a = 10; + constexpr int b = 100; + constexpr int c = 50; + SECTION("Going up works") { + auto r = range(a, a+2); + Vec v(std::begin(r), std::end(r)); + Vec vc{a, a+1}; + REQUIRE( v == vc ); + } + + SECTION("Going down works") { + auto r = range(a+2, a, -1); + Vec v(std::begin(r), std::end(r)); + Vec vc{a+2, a+1}; + REQUIRE( v == vc ); + } + + SECTION("Going down with -2 stop works") { + auto r = range(a+4, a, -2); + Vec v(std::begin(r), std::end(r)); + Vec vc{a+4, a+2}; + REQUIRE( v == vc ); + } + + SECTION("Using three variable") { + auto r = range(a, b, c); + Vec v(std::begin(r), std::end(r)); + REQUIRE( std::find(std::begin(v), std::end(v), a) != std::end(v) ); + REQUIRE( std::find(std::begin(v), std::end(v), b) == std::end(v) ); + REQUIRE( v.size() == 2 ); + } + + SECTION("Using three with a unary negate on step") { + auto r = range(b, a, -c); + Vec v(std::begin(r), std::end(r)); + + REQUIRE( std::find(std::begin(v), std::end(v), b) != std::end(v) ); + REQUIRE( std::find(std::begin(v), std::end(v), a) == std::end(v) ); + REQUIRE( v.size() == 2 ); + } + + SECTION("Using all three negated") { + auto r = range(-a, -b, -c); + Vec v(std::begin(r), std::end(r)); + + REQUIRE( std::find(std::begin(v), std::end(v), -a) != std::end(v) ); + REQUIRE( std::find(std::begin(v), std::end(v), -b) == std::end(v) ); + REQUIRE( v.size() == 2 ); + } + +} From 15e0a89e12b3e7b4bd8120d66aa3e622ffb8a2e7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 13 Nov 2014 10:58:27 -0500 Subject: [PATCH 0550/1866] Has IterYeild inherit from pair I feel this may be a controversial decision, but if I had the chance I'd probably go back to when I first made the enumerate decision and replace IterYield with a pair completely. index and element are just "aliases" for the data members in pair --- enumerate.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 52ee3db5..cb798363 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -43,6 +43,9 @@ namespace iter { friend Enumerable> enumerate( std::initializer_list); + // for IterYield + using BasePair = std::pair> ; + // Value constructor for use only in the enumerate function Enumerable(Container container) : container(std::forward(container)) @@ -51,14 +54,11 @@ namespace iter { public: // "yielded" by the Enumerable::Iterator. Has a .index, and a // .element referencing the value yielded by the subiterator - class IterYield { + class IterYield : public BasePair { public: - std::size_t index; - iterator_deref element; - IterYield(std::size_t i, iterator_deref elem) - : index{i}, - element{elem} - { } + using BasePair::BasePair; + decltype(BasePair::first)& index = BasePair::first; + decltype(BasePair::second)& element = BasePair::second; }; // Holds an iterator of the contained type and a size_t for the From bd3e652afb1610df62729738642eef5708292109 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 13 Nov 2014 11:00:36 -0500 Subject: [PATCH 0551/1866] enumerate iterator marked as forward_iterator --- enumerate.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index cb798363..659d2c0a 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -44,7 +44,7 @@ namespace iter { std::initializer_list); // for IterYield - using BasePair = std::pair> ; + using BasePair = std::pair>; // Value constructor for use only in the enumerate function Enumerable(Container container) @@ -64,7 +64,9 @@ namespace iter { // Holds an iterator of the contained type and a size_t for the // index. Each call to ++ increments both of these data members. // Each dereference returns an IterYield. - class Iterator { + class Iterator : + public std::iterator + { private: iterator_type sub_iter; std::size_t index; From 62ab6c4cc369bd65d94bdd0e40762e114d306de1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 13 Nov 2014 11:44:49 -0500 Subject: [PATCH 0552/1866] removes run_test_range.cpp --- catchtest/run_test_range.cpp | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 catchtest/run_test_range.cpp diff --git a/catchtest/run_test_range.cpp b/catchtest/run_test_range.cpp deleted file mode 100644 index 0c7c351f..00000000 --- a/catchtest/run_test_range.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#define CATCH_CONFIG_MAIN -#include "catch.hpp" From 5d81b565bfeea445c4bf0fc803fe9b3dd450d6b2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 13 Nov 2014 11:45:39 -0500 Subject: [PATCH 0553/1866] range iterator marked as forward iterator --- range.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/range.hpp b/range.hpp index 53752a3f..95ed6d8d 100644 --- a/range.hpp +++ b/range.hpp @@ -17,6 +17,7 @@ #include #include +#include namespace iter { @@ -63,7 +64,9 @@ namespace iter { public: Range() = delete; Range(const Range&) = default; - class Iterator { + class Iterator : + public std::iterator + { private: T value; T step; From 72a711e7af0354b1ba7a9e4d4738464bfe830422 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 13 Nov 2014 11:46:09 -0500 Subject: [PATCH 0554/1866] Adds basic catch test for enumerate --- catchtest/Makefile | 11 ++++++----- catchtest/test_enumerate.cpp | 27 +++++++++++++++++++++++++++ catchtest/test_main.cpp | 2 ++ 3 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 catchtest/test_enumerate.cpp create mode 100644 catchtest/test_main.cpp diff --git a/catchtest/Makefile b/catchtest/Makefile index c3ba6c57..6e26db78 100644 --- a/catchtest/Makefile +++ b/catchtest/Makefile @@ -1,13 +1,14 @@ CXX = g++ -CXXFLAGS = -Wall -Wextra -pedantic -std=c++11 +CXXFLAGS = -Wall -Wextra -pedantic -std=c++11 -fdiagnostics-color=auto CPPFLAGS = -I.. LINK.o = $(CXX) -all: test_range +all: test_main -test_range: test_range.o run_test_range.o +test_main: test_main.o test_range.o test_enumerate.o -test_range.o: test_range.cpp +test_range.o: test_range.cpp ../range.hpp +test_enumerate.o: test_enumerate.cpp ../enumerate.hpp clean: - rm -f test_range *.o + rm -f test_main *.o diff --git a/catchtest/test_enumerate.cpp b/catchtest/test_enumerate.cpp new file mode 100644 index 00000000..c6253e9f --- /dev/null +++ b/catchtest/test_enumerate.cpp @@ -0,0 +1,27 @@ +#include + +#include +#include +#include +#include + +#include "catch.hpp" + +using Vec = std::vector>; +using iter::enumerate; + +TEST_CASE("Basic Function", "[enumerate]") { + std::string str = "abc"; + auto e = enumerate(str); + Vec v(std::begin(e), std::end(e)); + Vec vc{{0, 'a'}, {1, 'b'}, {2, 'c'}}; + + REQUIRE( v == vc ); +} + +TEST_CASE("Empty", "[enumerate]") { + std::string emp{}; + auto e = enumerate(emp); + Vec v(std::begin(e), std::end(e)); + REQUIRE( v.empty() ); +} diff --git a/catchtest/test_main.cpp b/catchtest/test_main.cpp new file mode 100644 index 00000000..0c7c351f --- /dev/null +++ b/catchtest/test_main.cpp @@ -0,0 +1,2 @@ +#define CATCH_CONFIG_MAIN +#include "catch.hpp" From 602f3d2710e159f2175db4cba018c30f5c3a966b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 14 Nov 2014 00:15:51 -0500 Subject: [PATCH 0555/1866] marks enumerate iterator as forward_iterator --- enumerate.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enumerate.hpp b/enumerate.hpp index 659d2c0a..93592838 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -65,7 +65,7 @@ namespace iter { // index. Each call to ++ increments both of these data members. // Each dereference returns an IterYield. class Iterator : - public std::iterator + public std::iterator { private: iterator_type sub_iter; From 3bab276571b568464d91b3ff9d5ea4eb86889a5a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Nov 2014 21:07:57 -0500 Subject: [PATCH 0556/1866] adds more serious tests for enumerate --- catchtest/test_enumerate.cpp | 48 ++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/catchtest/test_enumerate.cpp b/catchtest/test_enumerate.cpp index c6253e9f..fc3f8e78 100644 --- a/catchtest/test_enumerate.cpp +++ b/catchtest/test_enumerate.cpp @@ -4,6 +4,16 @@ #include #include #include +#include + +namespace Catch { +template +std::string toString( const std::pair& p) { + std::ostringstream oss; + oss << '{' << p.first << ", " << p.second << '}'; + return oss.str(); +} +} #include "catch.hpp" @@ -23,5 +33,43 @@ TEST_CASE("Empty", "[enumerate]") { std::string emp{}; auto e = enumerate(emp); Vec v(std::begin(e), std::end(e)); + REQUIRE( v.empty() ); } + +TEST_CASE("Modifications through enumerate affect container", "[enumerate]") { + std::vector v{1, 2, 3, 4}; + std::vector vc(v.size(), -1); + for (auto&& p : enumerate(v)){ + p.second = -1; + } + + REQUIRE( v == vc ); +} + +TEST_CASE("Static array works", "[enumerate]") { + char arr[] = {'w', 'x', 'y'}; + + SECTION("Conversion to vector") { + auto e = enumerate(arr); + Vec v(std::begin(e), std::end(e)); + Vec vc{{0, 'w'}, {1, 'x'}, {2, 'y'}}; + REQUIRE( v == vc ); + } + + SECTION("Modification through enumerate") { + for (auto&& p : enumerate(arr)) { + p.second = 'z'; + } + std::vector v(std::begin(arr), std::end(arr)); + decltype(v) vc(v.size(), 'z'); + REQUIRE( v == vc ); + } +} + +TEST_CASE("initializer_list works", "[enumerate]") { + auto e = enumerate({'a', 'b', 'c'}); + Vec v(std::begin(e), std::end(e)); + Vec vc{{0, 'a'}, {1, 'b'}, {2, 'c'}}; + REQUIRE( v == vc ); +} From b488fc5a963cb34e123dfe3eb56c7a7ba75ccd1c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Nov 2014 22:41:51 -0500 Subject: [PATCH 0557/1866] adds minimal requirements for testing --- catchtest/test_helpers.hpp | 119 +++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 catchtest/test_helpers.hpp diff --git a/catchtest/test_helpers.hpp b/catchtest/test_helpers.hpp new file mode 100644 index 00000000..175434e0 --- /dev/null +++ b/catchtest/test_helpers.hpp @@ -0,0 +1,119 @@ +#ifndef TEST_HELPER_H_ +#define TEST_HELPER_H_ + +namespace itertest { + +// move-constructible only int wrapper +class SolidInt { + private: + const int i; + public: + constexpr SolidInt(int n) + : i{n} + { } + + constexpr int getint() const { + return this->i; + } + + SolidInt() = delete; + SolidInt(const SolidInt&) = delete; + constexpr SolidInt(SolidInt&&) noexcept = default; + SolidInt& operator=(const SolidInt&) = delete; + SolidInt& operator=(SolidInt&&) = delete; +}; + + +// BasicIterable provides a minimal forward iterator +// operator++(), operator!=(const BasicIterable&), operator*() +// move constructible only +// not copy constructible, move assignable, or copy assignable +template +class BasicIterable { + private: + T *data; + std::size_t size; + bool was_moved_from_ = false; + bool was_copied_from_ = false; + public: + BasicIterable(std::initializer_list il) + : data{new T[il.size()]}, + size{il.size()} + { + // would like to use enumerate, can't because it's for unit + // testing enumerate + std::size_t i = 0; + for (auto&& e : il) { + data[i] = e; + ++i; + } + } + + BasicIterable& operator=(BasicIterable&&) = delete; + 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}, + size{other.size} + { + other.data = nullptr; + other.was_moved_from_ = true; + } + + bool was_moved_from() const { + return this->was_moved_from_; + } + + bool was_copied_from() const { + return this->was_copied_from_; + } + + ~BasicIterable() { + delete [] this->data; + } + + class Iterator { + private: + T *p; + public: + Iterator(T *b) : p{b} { } + bool operator!=(const Iterator& other) const { + return this->p != other.p; + } + + Iterator& operator++() { + ++this->p; + } + + T& operator*() { + return *this->p; + } + }; + + Iterator begin() { + return {this->data}; + } + + Iterator end() { + return {this->data + this->size}; + } +}; + +} + +#endif From b8c5c9543eb115be80365c8faf6c24bfd12c5cea Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Nov 2014 22:42:14 -0500 Subject: [PATCH 0558/1866] tests enumerate with minimal requirements --- catchtest/test_enumerate.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/catchtest/test_enumerate.cpp b/catchtest/test_enumerate.cpp index fc3f8e78..b2832c6e 100644 --- a/catchtest/test_enumerate.cpp +++ b/catchtest/test_enumerate.cpp @@ -1,5 +1,7 @@ #include +#include "test_helpers.hpp" + #include #include #include @@ -20,6 +22,9 @@ std::string toString( const std::pair& p) { using Vec = std::vector>; using iter::enumerate; +using itertest::BasicIterable; +using itertest::SolidInt; + TEST_CASE("Basic Function", "[enumerate]") { std::string str = "abc"; auto e = enumerate(str); @@ -73,3 +78,24 @@ TEST_CASE("initializer_list works", "[enumerate]") { Vec vc{{0, 'a'}, {1, 'b'}, {2, 'c'}}; REQUIRE( v == vc ); } + +TEST_CASE("binds reference when it should", "[enumerate]") { + BasicIterable bi{'x', 'y', 'z'}; + auto e = enumerate(bi); + (void)e; + REQUIRE_FALSE( bi.was_moved_from() ); +} + +TEST_CASE("moves rvalues into enumerable object", "[enumerate]") { + BasicIterable bi{'x', 'y', 'z'}; + auto e = enumerate(std::move(bi)); + REQUIRE( bi.was_moved_from()); + (void)e; +} + +TEST_CASE("Doesn't move or copy elements of iterable", "[enumerate]") { + constexpr SolidInt arr[] = {6, 7, 8}; + for (auto&& i : enumerate(arr)) { + (void)i; + } +} From 2b81f4adc296a495836b29e93af638448b7a32b3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Nov 2014 23:03:33 -0500 Subject: [PATCH 0559/1866] adds catch test gitignore --- catchtest/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 catchtest/.gitignore diff --git a/catchtest/.gitignore b/catchtest/.gitignore new file mode 100644 index 00000000..f3f25933 --- /dev/null +++ b/catchtest/.gitignore @@ -0,0 +1,2 @@ +*.o +test_main From a6df6d8139524ca67b5f4a3984bf3824793ed109 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 22 Nov 2014 17:59:07 -0500 Subject: [PATCH 0560/1866] zip iterator inherits from std::iterator --- zip.hpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/zip.hpp b/zip.hpp index 08d2ec1a..240ee0f5 100644 --- a/zip.hpp +++ b/zip.hpp @@ -18,8 +18,9 @@ namespace iter { // specialization for at least 1 template argument template class Zipped { - static_assert(!std::is_rvalue_reference::value, - "Itertools cannot be templated with rvalue references"); + using ZipIterDeref = + std::tuple, + iterator_deref...>; friend Zipped zip( Container&&, RestContainers&&...); @@ -36,7 +37,9 @@ namespace iter { { } public: - class Iterator { + class Iterator : + public std::iterator + { private: using RestIter = typename Zipped::Iterator; @@ -90,7 +93,9 @@ namespace iter { template <> class Zipped<> { public: - class Iterator { + class Iterator + : public std::iterator> + { public: constexpr static const bool is_base_iter = true; From ca5b9ede248851f426bf511b19cf664be9d3ef9b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 22 Nov 2014 18:02:19 -0500 Subject: [PATCH 0561/1866] basic zip test --- catchtest/test_zip.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 catchtest/test_zip.cpp diff --git a/catchtest/test_zip.cpp b/catchtest/test_zip.cpp new file mode 100644 index 00000000..3f836322 --- /dev/null +++ b/catchtest/test_zip.cpp @@ -0,0 +1,28 @@ +#include + +#include "test_helpers.hpp" + +#include +#include +#include +#include +#include +#include + +#include "catch.hpp" + +using iter::zip; + +TEST_CASE("Simple case, same length", "[zip]") { + using Tu = std::tuple; + using ResVec = const std::vector; + std::vector iv {10, 20, 30}; + std::string s{"hey"}; + double arr[] = {1.0, 2.0, 4.0}; + + auto z = zip(iv, s, arr); + ResVec v(std::begin(z), std::end(z)); + ResVec vc {Tu{10, 'h', 1.0}, Tu{20, 'e', 2.0}, Tu{30, 'y', 4.0}}; + REQUIRE( v == vc ); +} + From 909e0324c6858c63600def5ee8c3c49abcefae3a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 22 Nov 2014 18:02:32 -0500 Subject: [PATCH 0562/1866] adds test_zip to main catch test --- catchtest/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/catchtest/Makefile b/catchtest/Makefile index 6e26db78..16cd013d 100644 --- a/catchtest/Makefile +++ b/catchtest/Makefile @@ -5,10 +5,11 @@ LINK.o = $(CXX) all: test_main -test_main: test_main.o test_range.o test_enumerate.o +test_main: test_main.o test_range.o test_enumerate.o test_zip.o test_range.o: test_range.cpp ../range.hpp test_enumerate.o: test_enumerate.cpp ../enumerate.hpp +test_zip.o: test_zip.cpp ../zip.hpp clean: rm -f test_main *.o From 3ee9977768352634bbaea821391c15a4a14c823b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Nov 2014 14:32:11 -0500 Subject: [PATCH 0563/1866] adds test for correct empty zip --- catchtest/test_zip.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/catchtest/test_zip.cpp b/catchtest/test_zip.cpp index 3f836322..309dc4a9 100644 --- a/catchtest/test_zip.cpp +++ b/catchtest/test_zip.cpp @@ -26,3 +26,11 @@ TEST_CASE("Simple case, same length", "[zip]") { REQUIRE( v == vc ); } +TEST_CASE("One empty, all empty", "[zip]") { + std::vector iv = {1,2,3}; + std::string s{}; + auto z = zip(iv, s); + REQUIRE_FALSE( std::begin(z) != std::end(z) ); + auto z2 = zip(s, iv); + REQUIRE_FALSE( std::begin(z2) != std::end(z2) ); +} From 06122d3295b2a9f7e72892a51027b9c604df2ceb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Nov 2014 14:35:14 -0500 Subject: [PATCH 0564/1866] adds enumerate test with const sequence --- catchtest/test_enumerate.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/catchtest/test_enumerate.cpp b/catchtest/test_enumerate.cpp index b2832c6e..b3c1f01a 100644 --- a/catchtest/test_enumerate.cpp +++ b/catchtest/test_enumerate.cpp @@ -93,6 +93,14 @@ TEST_CASE("moves rvalues into enumerable object", "[enumerate]") { (void)e; } +TEST_CASE("Works with const iterable", "[enumerate]") { + const std::string s{"ace"}; + auto e = enumerate(s); + Vec v(std::begin(e), std::end(e)); + Vec vc{{0, 'a'}, {1, 'c'}, {2, 'e'}}; + REQUIRE( v == vc ); +} + TEST_CASE("Doesn't move or copy elements of iterable", "[enumerate]") { constexpr SolidInt arr[] = {6, 7, 8}; for (auto&& i : enumerate(arr)) { From c107e8b4d9a71e34ba18aeb2b935c5e4fdbbd51a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Nov 2014 14:55:11 -0500 Subject: [PATCH 0565/1866] adds zip test for shortest sequence termination --- catchtest/test_zip.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/catchtest/test_zip.cpp b/catchtest/test_zip.cpp index 309dc4a9..bf8c8152 100644 --- a/catchtest/test_zip.cpp +++ b/catchtest/test_zip.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "catch.hpp" @@ -34,3 +35,12 @@ TEST_CASE("One empty, all empty", "[zip]") { auto z2 = zip(s, iv); REQUIRE_FALSE( std::begin(z2) != std::end(z2) ); } + +TEST_CASE("terminates on shortest sequence", "[zip]") { + std::vector iv{1,2,3,4,5}; + std::string s{"hi"}; + auto z = zip(iv, s); + + REQUIRE( std::distance(std::begin(z), std::end(z)) == 2 ); +} + From 0d00a525b9d0a969a9964890f68f7c064d6a3b8b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Nov 2014 14:55:30 -0500 Subject: [PATCH 0566/1866] adds test for empty zip() --- catchtest/test_zip.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/catchtest/test_zip.cpp b/catchtest/test_zip.cpp index bf8c8152..ee99a473 100644 --- a/catchtest/test_zip.cpp +++ b/catchtest/test_zip.cpp @@ -44,3 +44,7 @@ TEST_CASE("terminates on shortest sequence", "[zip]") { REQUIRE( std::distance(std::begin(z), std::end(z)) == 2 ); } +TEST_CASE("Empty zip()", "[zip]") { + auto z = zip(); + REQUIRE_FALSE( std::begin(z) != std::end(z) ); +} From 1b091c4460263ba64b5a89cd665f8f0ac7819af4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Nov 2014 14:56:03 -0500 Subject: [PATCH 0567/1866] tests for modifying iterables through zip --- catchtest/test_zip.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/catchtest/test_zip.cpp b/catchtest/test_zip.cpp index ee99a473..5bf41a67 100644 --- a/catchtest/test_zip.cpp +++ b/catchtest/test_zip.cpp @@ -48,3 +48,13 @@ TEST_CASE("Empty zip()", "[zip]") { auto z = zip(); REQUIRE_FALSE( std::begin(z) != std::end(z) ); } + +TEST_CASE("Modify sequence through zip", "[zip]") { + std::vector iv{1,2,3}; + for (auto&& t : zip(iv)) { + std::get<0>(t) = -1; + } + + const std::vector vc{-1, -1, -1}; + REQUIRE( iv == vc); +} From 71ae2777c1739476f2e2c3db2fc7a558a7df87c0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Nov 2014 15:02:10 -0500 Subject: [PATCH 0568/1866] tests zip for correct bind and move --- catchtest/test_zip.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/catchtest/test_zip.cpp b/catchtest/test_zip.cpp index 5bf41a67..8c7ec369 100644 --- a/catchtest/test_zip.cpp +++ b/catchtest/test_zip.cpp @@ -13,6 +13,8 @@ #include "catch.hpp" using iter::zip; +using itertest::BasicIterable; +using itertest::SolidInt; TEST_CASE("Simple case, same length", "[zip]") { using Tu = std::tuple; @@ -58,3 +60,23 @@ TEST_CASE("Modify sequence through zip", "[zip]") { const std::vector vc{-1, -1, -1}; REQUIRE( iv == vc); } + +TEST_CASE("Binds reference when it should", "[zip]") { + BasicIterable bi{'x', 'y', 'z'}; + zip(bi); + REQUIRE_FALSE( bi.was_moved_from() ); +} + +TEST_CASE("Moves rvalues", "[zip]") { + BasicIterable bi{'x', 'y', 'z'}; + zip(std::move(bi)); + REQUIRE( bi.was_moved_from() ); +} + +TEST_CASE("Can bind ref and move in single zip", "[zip]") { + BasicIterable b1{'x', 'y', 'z'}; + BasicIterable b2{'a', 'b'}; + zip(b1, std::move(b2)); + REQUIRE_FALSE( b1.was_moved_from() ); + REQUIRE( b2.was_moved_from() ); +} From e54c86c3d5a0bce3b12978fb2509d703de1ba32b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Nov 2014 15:10:05 -0500 Subject: [PATCH 0569/1866] soldint throws if two levels of moves happen --- catchtest/test_helpers.hpp | 15 ++++++++++++++- catchtest/test_zip.cpp | 11 +++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/catchtest/test_helpers.hpp b/catchtest/test_helpers.hpp index 175434e0..e5e1546f 100644 --- a/catchtest/test_helpers.hpp +++ b/catchtest/test_helpers.hpp @@ -1,12 +1,15 @@ #ifndef TEST_HELPER_H_ #define TEST_HELPER_H_ +#include + namespace itertest { // move-constructible only int wrapper class SolidInt { private: const int i; + bool moved_from = false; public: constexpr SolidInt(int n) : i{n} @@ -18,9 +21,19 @@ class SolidInt { SolidInt() = delete; SolidInt(const SolidInt&) = delete; - constexpr SolidInt(SolidInt&&) noexcept = default; SolidInt& operator=(const SolidInt&) = delete; SolidInt& operator=(SolidInt&&) = delete; + + SolidInt(SolidInt&& other) + : i{other.i} + { + if (other.moved_from) { + throw std::invalid_argument{ + "Object was constructed with a move ctor"}; + } + other.moved_from = true; + } + }; diff --git a/catchtest/test_zip.cpp b/catchtest/test_zip.cpp index 8c7ec369..06a409ba 100644 --- a/catchtest/test_zip.cpp +++ b/catchtest/test_zip.cpp @@ -61,13 +61,13 @@ TEST_CASE("Modify sequence through zip", "[zip]") { REQUIRE( iv == vc); } -TEST_CASE("Binds reference when it should", "[zip]") { +TEST_CASE("zip binds reference when it should", "[zip]") { BasicIterable bi{'x', 'y', 'z'}; zip(bi); REQUIRE_FALSE( bi.was_moved_from() ); } -TEST_CASE("Moves rvalues", "[zip]") { +TEST_CASE("zip moves rvalues", "[zip]") { BasicIterable bi{'x', 'y', 'z'}; zip(std::move(bi)); REQUIRE( bi.was_moved_from() ); @@ -80,3 +80,10 @@ TEST_CASE("Can bind ref and move in single zip", "[zip]") { REQUIRE_FALSE( b1.was_moved_from() ); REQUIRE( b2.was_moved_from() ); } + +TEST_CASE("zip doesn't move or copy elements of iterable", "[zip]") { + constexpr SolidInt arr[] = {6, 7, 8}; + for (auto&& t : zip(arr)) { + (void)std::get<0>(t); + } +} From ea91611df147ac2173441b0c64b5e60b32354eef Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Nov 2014 20:58:48 -0500 Subject: [PATCH 0570/1866] renames test_helpers to helpers --- catchtest/{test_helpers.hpp => helpers.hpp} | 0 catchtest/test_enumerate.cpp | 2 +- catchtest/test_zip.cpp | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename catchtest/{test_helpers.hpp => helpers.hpp} (100%) diff --git a/catchtest/test_helpers.hpp b/catchtest/helpers.hpp similarity index 100% rename from catchtest/test_helpers.hpp rename to catchtest/helpers.hpp diff --git a/catchtest/test_enumerate.cpp b/catchtest/test_enumerate.cpp index b3c1f01a..e9131fe5 100644 --- a/catchtest/test_enumerate.cpp +++ b/catchtest/test_enumerate.cpp @@ -1,6 +1,6 @@ #include -#include "test_helpers.hpp" +#include "helpers.hpp" #include #include diff --git a/catchtest/test_zip.cpp b/catchtest/test_zip.cpp index 06a409ba..f0c93914 100644 --- a/catchtest/test_zip.cpp +++ b/catchtest/test_zip.cpp @@ -1,6 +1,6 @@ #include -#include "test_helpers.hpp" +#include "helpers.hpp" #include #include From 915a889c4d0dcc3e89538314a2c490ffd5e87016 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Nov 2014 21:07:09 -0500 Subject: [PATCH 0571/1866] makes solidint throw at correct time --- catchtest/helpers.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/catchtest/helpers.hpp b/catchtest/helpers.hpp index e5e1546f..570373b0 100644 --- a/catchtest/helpers.hpp +++ b/catchtest/helpers.hpp @@ -9,7 +9,7 @@ namespace itertest { class SolidInt { private: const int i; - bool moved_from = false; + bool made_from_move = false; public: constexpr SolidInt(int n) : i{n} @@ -25,13 +25,13 @@ class SolidInt { SolidInt& operator=(SolidInt&&) = delete; SolidInt(SolidInt&& other) - : i{other.i} + : i{other.i}, + made_from_move{true} { - if (other.moved_from) { + if (other.made_from_move) { throw std::invalid_argument{ "Object was constructed with a move ctor"}; } - other.moved_from = true; } }; From 375af8665d28e3fd96aa065f0c471ed5b637cede Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Nov 2014 21:07:26 -0500 Subject: [PATCH 0572/1866] test_main tests the helpers --- catchtest/Makefile | 3 ++- catchtest/test_helpers.cpp | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 catchtest/test_helpers.cpp diff --git a/catchtest/Makefile b/catchtest/Makefile index 16cd013d..44032298 100644 --- a/catchtest/Makefile +++ b/catchtest/Makefile @@ -5,11 +5,12 @@ LINK.o = $(CXX) all: test_main -test_main: test_main.o test_range.o test_enumerate.o test_zip.o +test_main: test_main.o test_range.o test_enumerate.o test_zip.o test_helpers.o test_range.o: test_range.cpp ../range.hpp test_enumerate.o: test_enumerate.cpp ../enumerate.hpp test_zip.o: test_zip.cpp ../zip.hpp +test_helpers.o: test_helpers.cpp helpers.hpp clean: rm -f test_main *.o diff --git a/catchtest/test_helpers.cpp b/catchtest/test_helpers.cpp new file mode 100644 index 00000000..f3c59813 --- /dev/null +++ b/catchtest/test_helpers.cpp @@ -0,0 +1,17 @@ +#include "helpers.hpp" +#include + +#include "catch.hpp" + +using itertest::SolidInt; + +TEST_CASE("SolidInt can be moved only once", "[helpers]") { + SolidInt i{3}; + SECTION("Doesn't throw on first move") { + REQUIRE_NOTHROW( SolidInt{std::move(i)} ); + } + SECTION("Throws on second move") { + SolidInt i2{std::move(i)}; + REQUIRE_THROWS( SolidInt i3{std::move(i2)} ); + } +} From 0da2d5ce95f47fb592feaee41b35e9448f5f16f4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Nov 2014 21:10:08 -0500 Subject: [PATCH 0573/1866] tests modifying two sequences --- catchtest/test_zip.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/catchtest/test_zip.cpp b/catchtest/test_zip.cpp index f0c93914..1374feb1 100644 --- a/catchtest/test_zip.cpp +++ b/catchtest/test_zip.cpp @@ -53,12 +53,16 @@ TEST_CASE("Empty zip()", "[zip]") { TEST_CASE("Modify sequence through zip", "[zip]") { std::vector iv{1,2,3}; - for (auto&& t : zip(iv)) { + std::vector iv2{1,2,3,4}; + for (auto&& t : zip(iv, iv2)) { std::get<0>(t) = -1; + std::get<1>(t) = -1; } const std::vector vc{-1, -1, -1}; + const std::vector vc2{-1, -1, -1, 4}; REQUIRE( iv == vc); + REQUIRE( iv2 == vc2); } TEST_CASE("zip binds reference when it should", "[zip]") { From 372a85fb79437aeef0abf7a89840b44fcf680268 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Nov 2014 21:14:04 -0500 Subject: [PATCH 0574/1866] removes import platform --- tests/SConstruct | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/SConstruct b/tests/SConstruct index 626cb51a..74195c1e 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -1,4 +1,3 @@ -import platform import os env = Environment( From 3b1e72e020f21d59e5039468a9f29c9707e2a728 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Nov 2014 21:39:15 -0500 Subject: [PATCH 0575/1866] replaces makefile with SConstruct --- catchtest/Makefile | 16 ---------------- catchtest/SConstruct | 30 ++++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 16 deletions(-) delete mode 100644 catchtest/Makefile create mode 100644 catchtest/SConstruct diff --git a/catchtest/Makefile b/catchtest/Makefile deleted file mode 100644 index 44032298..00000000 --- a/catchtest/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -CXX = g++ -CXXFLAGS = -Wall -Wextra -pedantic -std=c++11 -fdiagnostics-color=auto -CPPFLAGS = -I.. -LINK.o = $(CXX) - -all: test_main - -test_main: test_main.o test_range.o test_enumerate.o test_zip.o test_helpers.o - -test_range.o: test_range.cpp ../range.hpp -test_enumerate.o: test_enumerate.cpp ../enumerate.hpp -test_zip.o: test_zip.cpp ../zip.hpp -test_helpers.o: test_helpers.cpp helpers.hpp - -clean: - rm -f test_main *.o diff --git a/catchtest/SConstruct b/catchtest/SConstruct new file mode 100644 index 00000000..574317c4 --- /dev/null +++ b/catchtest/SConstruct @@ -0,0 +1,30 @@ +import os + +env = Environment( + ENV = {'PATH' : os.environ['PATH']}, + CXX='c++', + CXXFLAGS= ['-g', '-Wall', '-Wextra', + '-pedantic', '-std=c++11', + '-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( + ''' + enumerate + zip + range + ''' +) + +test_sources = ['test_{}.cpp'.format(p) for p in progs] + +for test_src in test_sources: + env.Program([test_src, 'test_main.cpp']) + +env.Program('test_all', ['test_main.cpp'] + test_sources) + From cc292dbb76b4c1a64195a1d01b76a62efdc83742 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Nov 2014 21:42:48 -0500 Subject: [PATCH 0576/1866] ignores all test_ executables --- catchtest/.gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/catchtest/.gitignore b/catchtest/.gitignore index f3f25933..427dd64a 100644 --- a/catchtest/.gitignore +++ b/catchtest/.gitignore @@ -1,2 +1,4 @@ *.o -test_main +test_* +!test_*.cpp +.sconsign.dblite From ea3b49ba5ea7ec3bdaf5ca296ab7bc710cc8546e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Nov 2014 21:52:09 -0500 Subject: [PATCH 0577/1866] removes __ from include guards --- accumulate.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index ef4ed42c..9c7da049 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -1,5 +1,5 @@ -#ifndef ACCUMULATE__H__ -#define ACCUMULATE__H__ +#ifndef ITER_ACCUMULATE_H_ +#define ITER_ACCUMULATE_H_ #include "iterbase.hpp" @@ -143,4 +143,4 @@ namespace iter { } -#endif //ifndef ACCUMULATE__H__ +#endif //ifndef ITER_ACCUMULATE_H_ From 2994dee81967723614c6ef8c29585e4b1cd71885 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Nov 2014 21:56:02 -0500 Subject: [PATCH 0578/1866] tests basic accumulate --- catchtest/test_accumulate.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 catchtest/test_accumulate.cpp diff --git a/catchtest/test_accumulate.cpp b/catchtest/test_accumulate.cpp new file mode 100644 index 00000000..0783ecc9 --- /dev/null +++ b/catchtest/test_accumulate.cpp @@ -0,0 +1,19 @@ +#include + +#include +#include +#include + +#include "catch.hpp" + +using iter::accumulate; + +TEST_CASE("Simple sum", "[accumulate]") { + std::vector ns{1,2,3,4,5}; + auto a = accumulate(ns); + + const std::vector v(std::begin(a), std::end(a)); + const std::vector vc{1,3,6,10,15}; + REQUIRE( v == vc ); +} + From f03b28a51443c4349a2b30a5af033f018ac30c1f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Nov 2014 21:56:10 -0500 Subject: [PATCH 0579/1866] accumulate iterator inherits from std::iterator --- accumulate.hpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index 9c7da049..0ff49028 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -36,7 +36,16 @@ namespace iter { friend Accumulator, AF> accumulate( std::initializer_list, AF); - // Value constructor for use only in the accumulate function + // AccumVal must be default constructible + using AccumVal = + typename std::remove_reference< + typename std::result_of, + iterator_deref)>::type>::type; + static_assert( + std::is_default_constructible::value, + "Cannot accumulate a non-default constructible type"); + Accumulator(Container container, AccumulateFunc accumulate_func) : container(std::forward(container)), accumulate_func(accumulate_func) @@ -47,17 +56,9 @@ namespace iter { public: Accumulator(const Accumulator&) = default; - class Iterator { - // AccumVal must be default constructible - using AccumVal = - typename std::remove_reference< - typename std::result_of, - iterator_deref)>::type>::type; - static_assert( - std::is_default_constructible::value, - "Cannot accumulate a non-default constructible type"); - + class Iterator + : public std::iterator + { private: iterator_type sub_iter; const iterator_type sub_end; From 7872f85739c905eefabb218e0502badfb8dec395 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Nov 2014 21:56:43 -0500 Subject: [PATCH 0580/1866] builds test_accumulate --- catchtest/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index 574317c4..181a7ce4 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -18,6 +18,7 @@ progs = Split( enumerate zip range + accumulate ''' ) From c64f5463ac38fd001ff8c3b41887d03f1daeb4b7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Nov 2014 22:15:40 -0500 Subject: [PATCH 0581/1866] removes delete/default on accumulate ctor and = Let the compiler figure it out. --- accumulate.hpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index 0ff49028..9e810dc5 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -50,11 +50,7 @@ namespace iter { : container(std::forward(container)), accumulate_func(accumulate_func) { } - Accumulator() = delete; - Accumulator& operator=(const Accumulator&) = delete; - public: - Accumulator(const Accumulator&) = default; class Iterator : public std::iterator From bae980337ec83d27d03f05a3c0caf8c17258cb5b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Nov 2014 22:18:58 -0500 Subject: [PATCH 0582/1866] tests accumulate with BasicIterable --- catchtest/test_accumulate.cpp | 37 ++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/catchtest/test_accumulate.cpp b/catchtest/test_accumulate.cpp index 0783ecc9..c52feb33 100644 --- a/catchtest/test_accumulate.cpp +++ b/catchtest/test_accumulate.cpp @@ -1,4 +1,5 @@ #include +#include "helpers.hpp" #include #include @@ -7,13 +8,43 @@ #include "catch.hpp" using iter::accumulate; +using itertest::BasicIterable; +using Vec = const std::vector; TEST_CASE("Simple sum", "[accumulate]") { - std::vector ns{1,2,3,4,5}; + Vec ns{1,2,3,4,5}; auto a = accumulate(ns); - const std::vector v(std::begin(a), std::end(a)); - const std::vector vc{1,3,6,10,15}; + Vec v(std::begin(a), std::end(a)); + Vec vc{1,3,6,10,15}; REQUIRE( v == vc ); } +TEST_CASE("With subtraction lambda", "[accumulate]") { + Vec ns{5,4,3,2,1}; + auto a = accumulate(ns, [](int a, int b){return a - b; }); + + Vec v(std::begin(a), std::end(a)); + Vec vc{5, 1, -2, -4, -5}; + REQUIRE( v == vc ); +} + +TEST_CASE("initializer_list works", "[accumulate]") { + auto a = accumulate({1, 2, 3}); + Vec v(std::begin(a), std::end(a)); + Vec vc{1, 3, 6}; + + REQUIRE( v == vc ); +} + +TEST_CASE("binds reference when it should", "[enumerate]") { + BasicIterable bi{1, 2}; + accumulate(bi); + REQUIRE_FALSE( bi.was_moved_from() ); +} + +TEST_CASE("moves rvalues into enumerable object", "[enumerate]") { + BasicIterable bi{1, 2}; + accumulate(std::move(bi)); + REQUIRE( bi.was_moved_from() ); +} From 17c32b76054ea8cfccd1cf6addfc9067233333bd Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Nov 2014 22:22:46 -0500 Subject: [PATCH 0583/1866] iterator dereferences to const ref to avoid copy --- accumulate.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accumulate.hpp b/accumulate.hpp index 9e810dc5..362e5a35 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -71,7 +71,7 @@ namespace iter { acc_val(!(iter != end) ? AccumVal{} : *iter) { } - AccumVal operator*() const { + const AccumVal& operator*() const { return this->acc_val; } From e6a83dc18210be2d6a073d76e722884886553104 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 24 Nov 2014 00:28:23 -0500 Subject: [PATCH 0584/1866] replace enumerate tag in accumulate tests --- catchtest/test_accumulate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/catchtest/test_accumulate.cpp b/catchtest/test_accumulate.cpp index c52feb33..f251dd03 100644 --- a/catchtest/test_accumulate.cpp +++ b/catchtest/test_accumulate.cpp @@ -37,13 +37,13 @@ TEST_CASE("initializer_list works", "[accumulate]") { REQUIRE( v == vc ); } -TEST_CASE("binds reference when it should", "[enumerate]") { +TEST_CASE("binds reference when it should", "[accumulate]") { BasicIterable bi{1, 2}; accumulate(bi); REQUIRE_FALSE( bi.was_moved_from() ); } -TEST_CASE("moves rvalues into enumerable object", "[enumerate]") { +TEST_CASE("moves rvalues into accumulator object", "[accumulate]") { BasicIterable bi{1, 2}; accumulate(std::move(bi)); REQUIRE( bi.was_moved_from() ); From e637d257d37e66ef97e5bfab97f9b4c4335bec55 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 24 Nov 2014 00:28:58 -0500 Subject: [PATCH 0585/1866] Removes boost_tests it wasn't gonna happen --- boost_tests/.gitignore | 3 - boost_tests/SConstruct | 31 ------- boost_tests/pattern_files/zip_output.txt | 36 -------- boost_tests/testzip.cpp | 106 ----------------------- 4 files changed, 176 deletions(-) delete mode 100644 boost_tests/.gitignore delete mode 100644 boost_tests/SConstruct delete mode 100644 boost_tests/pattern_files/zip_output.txt delete mode 100644 boost_tests/testzip.cpp diff --git a/boost_tests/.gitignore b/boost_tests/.gitignore deleted file mode 100644 index 5d88f468..00000000 --- a/boost_tests/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.o -*.dblite -testzip diff --git a/boost_tests/SConstruct b/boost_tests/SConstruct deleted file mode 100644 index 13eb390c..00000000 --- a/boost_tests/SConstruct +++ /dev/null @@ -1,31 +0,0 @@ -import platform -import os - -env = Environment( - CXX='c++', - CXXFLAGS= ['-g', '-Wall', '-Wextra', '-Weffc++', '-Wno-unused-parameter' , - '-pedantic', '-std=c++11', - '-I/usr/local/include', '-I/opt/local/include'], - CPPPATH='..', - LINKFLAGS=['-L/usr/local/lib', '-L/opt/local/lib'] - ) - -# allows highighting to print to terminal from compiler output -env['ENV']['TERM'] = os.environ['TERM'] - -# if on MAC, needs the linker flag for -stdlib=libc++ -# obselete with mavericks -""" if platform.system() == 'Darwin': - env['CXX'] += '-stdlib=libc++' - env['CXXFLAGS'].append('-stdlib=libc++') -""" - - - -progs = Split( ''' - zip - ''') - - -for p in progs: - env.Program('test{0}.cpp'.format(p)) diff --git a/boost_tests/pattern_files/zip_output.txt b/boost_tests/pattern_files/zip_output.txt deleted file mode 100644 index f2ea8edd..00000000 --- a/boost_tests/pattern_files/zip_output.txt +++ /dev/null @@ -1,36 +0,0 @@ -1 -hello -4 -good day -9 -goodbye -69 -hello -69 -good day -69 -goodbye - -Variadic template zip iterator -1 1.2 i 1.2 -2 1.4 like 1.2 -3 12.3 apples 1.2 -4 4.5 alot 1.2 - -1 i 2.2 1.2 -2 like 2.2 1.2 -3 apples 2.2 1.2 -4 alot 2.2 1.2 - -Try some weird range differences - - -2.2 i 1 1.2 -2.2 like 2 1.2 -2.2 apples 3 1.2 -2.2 alot 4 1.2 - -1 asdfas 1.1 -5 aaron 2.2 -1 ryan 3.3 -2 apple 4.4 diff --git a/boost_tests/testzip.cpp b/boost_tests/testzip.cpp deleted file mode 100644 index 802924d3..00000000 --- a/boost_tests/testzip.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "../zip.hpp" -#include "../chain.hpp" -#include -#include -#include -#include - -#define BOOST_TEST_MODULE ZipTest test - -#ifdef COMPILED_BINARY - #include -#else - #include -#endif - -#include -using boost::test_tools::output_test_stream; - - -using iter::zip; - -BOOST_AUTO_TEST_CASE ( zip_test ) { - - output_test_stream output("pattern_files/zip_output.txt",true); - //Ryan's test - { - std::vector ivec{1, 4, 9, 16, 25, 36}; - std::vector svec{"hello", "good day", "goodbye"}; - - for (auto e : zip(ivec, svec)) { - auto &i = std::get<0>(e); - output << i << std::endl; - i = 69; - output << std::get<1>(e) << std::endl; - } - BOOST_REQUIRE(output.match_pattern()); - for (auto e : zip(ivec, svec)) { - output << std::get<0>(e) << std::endl; - output << std::get<1>(e) << std::endl; - } - BOOST_REQUIRE(output.match_pattern()); - } - //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}}; - output << std::endl << "Variadic template zip iterator" << std::endl; - for (auto e : iter::zip(i,f,s,d)) { - output << 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 - } - output<(e) << " " - << std::get<1>(e) << " " - << std::get<2>(e) << " " - << std::get<3>(e) << std::endl; - } - BOOST_REQUIRE(output.match_pattern()); - output << std::endl << "Try some weird range differences" << std::endl; - std::vector empty{}; - for (auto e : iter::zip(empty,f,s,d)) { - output << std::get<0>(e) << " " - << std::get<1>(e) << " " - << std::get<2>(e) << " " - << std::get<3>(e) << std::endl; - } - output<(e) << " " - << std::get<1>(e) << " " - << std::get<2>(e) << " " - << std::get<3>(e) << std::endl; - }//both should print nothing - output<(e) << " " - << std::get<1>(e) << " " - << std::get<2>(e) << " " - << std::get<3>(e) << std::endl; - } - output< constvector{1.1,2.2,3.3,4.4}; - for (auto e : zip(iter::chain(std::vector{1,5},std::array{{1,2}}), - std::initializer_list{"asdfas","aaron","ryan","apple","juice"}, - constvector)) - { - - output << std::get<0>(e) << " " - << std::get<1>(e) << " " - << std::get<2>(e) << std::endl; - } - BOOST_REQUIRE(output.match_pattern()); - } - BOOST_REQUIRE(output.match_pattern()); -} - From 3dbb274b48cbd24838fe83b4fcec8cc90bd258d9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 26 Nov 2014 16:41:51 -0500 Subject: [PATCH 0586/1866] differs accumulate test names from enumerate --- catchtest/test_accumulate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/catchtest/test_accumulate.cpp b/catchtest/test_accumulate.cpp index f251dd03..a1cbf92e 100644 --- a/catchtest/test_accumulate.cpp +++ b/catchtest/test_accumulate.cpp @@ -29,7 +29,7 @@ TEST_CASE("With subtraction lambda", "[accumulate]") { REQUIRE( v == vc ); } -TEST_CASE("initializer_list works", "[accumulate]") { +TEST_CASE("accumulate with initializer_list works", "[accumulate]") { auto a = accumulate({1, 2, 3}); Vec v(std::begin(a), std::end(a)); Vec vc{1, 3, 6}; @@ -37,7 +37,7 @@ TEST_CASE("initializer_list works", "[accumulate]") { REQUIRE( v == vc ); } -TEST_CASE("binds reference when it should", "[accumulate]") { +TEST_CASE("accumulate binds reference when it should", "[accumulate]") { BasicIterable bi{1, 2}; accumulate(bi); REQUIRE_FALSE( bi.was_moved_from() ); From e67b6fd5ecd14f53c6eb59cbfbbcb3e2ef1867a2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 26 Nov 2014 16:42:03 -0500 Subject: [PATCH 0587/1866] zip iters are input not forward --- zip.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zip.hpp b/zip.hpp index 240ee0f5..cda4c5c4 100644 --- a/zip.hpp +++ b/zip.hpp @@ -38,7 +38,7 @@ namespace iter { public: class Iterator : - public std::iterator + public std::iterator { private: using RestIter = @@ -94,7 +94,7 @@ namespace iter { class Zipped<> { public: class Iterator - : public std::iterator> + : public std::iterator> { public: constexpr static const bool is_base_iter = true; From 04a4d373d2401f22d3b9e0f73959e1590d213c71 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 26 Nov 2014 16:42:45 -0500 Subject: [PATCH 0588/1866] accumulate iterators are input not forward --- accumulate.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accumulate.hpp b/accumulate.hpp index 362e5a35..013a6b2e 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -53,7 +53,7 @@ namespace iter { public: class Iterator - : public std::iterator + : public std::iterator { private: iterator_type sub_iter; From 46a4fad931ebb40eb84683887c74c906404ddff2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 26 Nov 2014 17:53:46 -0500 Subject: [PATCH 0589/1866] chain iterators inherit from std::iterator --- chain.hpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/chain.hpp b/chain.hpp index 3d4dc723..10d8a9ac 100644 --- a/chain.hpp +++ b/chain.hpp @@ -19,6 +19,9 @@ namespace iter { friend class ChainMaker; template friend class Chained; + + using iter_traits_deref = + typename std::remove_reference>::type; private: Container container; @@ -29,7 +32,10 @@ namespace iter { { } public: - class Iterator { + class Iterator + : public std::iterator< + std::input_iterator_tag, iter_traits_deref> + { private: using RestIter = typename Chained::Iterator; @@ -89,6 +95,9 @@ namespace iter { template friend class Chained; + using iter_traits_deref = + typename std::remove_reference>::type; + private: Container container; Chained(Container container) @@ -96,7 +105,10 @@ namespace iter { { } public: - class Iterator { + class Iterator + : public std::iterator< + std::input_iterator_tag, iter_traits_deref> + { private: iterator_type sub_iter; const iterator_type sub_end; From a24422117617b0af1ad0e4aece08cd1005d21048 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 26 Nov 2014 17:54:14 -0500 Subject: [PATCH 0590/1866] adds basic chain test --- catchtest/test_chain.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 catchtest/test_chain.cpp diff --git a/catchtest/test_chain.cpp b/catchtest/test_chain.cpp new file mode 100644 index 00000000..1feac050 --- /dev/null +++ b/catchtest/test_chain.cpp @@ -0,0 +1,26 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include "catch.hpp" + +using iter::chain; +using Vec = const std::vector; + +TEST_CASE("chain three strings", "[chain]") { + std::string s1{"abc"}; + std::string s2{"mno"}; + std::string s3{"xyz"}; + auto ch = chain(s1, s2, s3); + + Vec v(std::begin(ch), std::end(ch)); + Vec vc{'a','b','c','m','n','o','x','y','z'}; + + REQUIRE( v == vc ); +} + From 905669eeb0eb99ff3f3c49d5e5ff060fd63c2aa5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 26 Nov 2014 17:54:27 -0500 Subject: [PATCH 0591/1866] makes scons build chain test --- catchtest/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index 181a7ce4..e048c8b9 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -19,6 +19,7 @@ progs = Split( zip range accumulate + chain ''' ) From 9340b9ad91cf4502887c9ce0d410ddb7cde61520 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 26 Nov 2014 18:09:01 -0500 Subject: [PATCH 0592/1866] chain uses static_assert to check contained types static_assert is triggered when iterator_deref isn't the same for all containers. I have added an are_same to iterbase to do the checking. it's basically a variadic version of std::is_same. --- chain.hpp | 7 +++++++ iterbase.hpp | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/chain.hpp b/chain.hpp index 10d8a9ac..5029a9df 100644 --- a/chain.hpp +++ b/chain.hpp @@ -16,6 +16,13 @@ namespace iter { template class Chained { + static_assert( + are_same, + iterator_deref...>::value, + "All chained iterables must have iterators that " + "dereference to the same type, including cv-qualifiers " + "and references."); + friend class ChainMaker; template friend class Chained; diff --git a/iterbase.hpp b/iterbase.hpp index 15f0a0a0..76eee7b5 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -79,6 +79,18 @@ namespace iter { typename std::remove_const< iterator_deref>::type>::type; + + template + struct are_same { + constexpr static bool value = true; + }; + + template + struct are_same { + constexpr static bool value = + std::is_same::value && are_same::value; + }; + } #endif // #ifndef ITERBASE_HPP_ From 43ba5c7d9a7b3d10829e22b7276772e73200dadd Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 26 Nov 2014 18:34:35 -0500 Subject: [PATCH 0593/1866] tests chain with different container types --- catchtest/test_chain.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/catchtest/test_chain.cpp b/catchtest/test_chain.cpp index 1feac050..0831abd1 100644 --- a/catchtest/test_chain.cpp +++ b/catchtest/test_chain.cpp @@ -24,3 +24,14 @@ TEST_CASE("chain three strings", "[chain]") { REQUIRE( v == vc ); } +TEST_CASE("chain with different container types", "[chain]") { + std::string s1{"abc"}; + std::list li{'m', 'n', 'o'}; + std::vector vec{'x', 'y', 'z'}; + auto ch = chain(s1, li, vec); + + Vec v(std::begin(ch), std::end(ch)); + Vec vc{'a','b','c','m','n','o','x','y','z'}; + + REQUIRE( v == vc ); +} From 6eeebecf45b4dbd921bf57d1720121c54947e764 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 26 Nov 2014 18:54:12 -0500 Subject: [PATCH 0594/1866] adds chain test with empty containers throughout --- catchtest/test_chain.cpp | 50 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/catchtest/test_chain.cpp b/catchtest/test_chain.cpp index 0831abd1..4f716aa7 100644 --- a/catchtest/test_chain.cpp +++ b/catchtest/test_chain.cpp @@ -35,3 +35,53 @@ TEST_CASE("chain with different container types", "[chain]") { REQUIRE( v == vc ); } + +TEST_CASE("chain handles empty containers", "[chain]") { + std::string emp; + std::string a{"a"}; + std::string b{"b"}; + std::string c{"c"}; + Vec vc{'a', 'b', 'c'}; + + SECTION("Empty container at front") { + auto ch = chain(emp, a, b, c); + Vec v(std::begin(ch), std::end(ch)); + + REQUIRE( v == vc ); + } + + SECTION("Empty container at back") { + auto ch = chain(a, b, c, emp); + Vec v(std::begin(ch), std::end(ch)); + + REQUIRE( v == vc ); + } + + SECTION("Empty container in middle") { + auto ch = chain(a, emp, b, emp, c); + Vec v(std::begin(ch), std::end(ch)); + + REQUIRE( v == vc ); + } + + SECTION("Consecutive empty containers at front") { + auto ch = chain(emp, emp, a, b, c); + Vec v(std::begin(ch), std::end(ch)); + + REQUIRE( v == vc ); + } + + SECTION("Consecutive empty containers at back") { + auto ch = chain(a, b, c, emp, emp); + Vec v(std::begin(ch), std::end(ch)); + + REQUIRE( v == vc ); + } + + SECTION("Consecutive empty containers in middle") { + auto ch = chain(a, emp, emp, b, emp, emp, c); + Vec v(std::begin(ch), std::end(ch)); + + REQUIRE( v == vc ); + } +} From e72ff1038a0318be44937dcac381edf0722a4c82 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 26 Nov 2014 18:56:53 -0500 Subject: [PATCH 0595/1866] adds chain tests with only empty containers --- catchtest/test_chain.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/catchtest/test_chain.cpp b/catchtest/test_chain.cpp index 4f716aa7..e01dbed5 100644 --- a/catchtest/test_chain.cpp +++ b/catchtest/test_chain.cpp @@ -85,3 +85,21 @@ TEST_CASE("chain handles empty containers", "[chain]") { REQUIRE( v == vc ); } } + +TEST_CASE("chain with only empty containers", "[chain]") { + std::string emp{}; + SECTION("one empty container") { + auto ch = chain(emp); + REQUIRE_FALSE( std::begin(ch) != std::end(ch) ); + } + + SECTION("two empty containers") { + auto ch = chain(emp, emp); + REQUIRE_FALSE( std::begin(ch) != std::end(ch) ); + } + + SECTION("three empty containers") { + auto ch = chain(emp, emp, emp); + REQUIRE_FALSE( std::begin(ch) != std::end(ch) ); + } +} From d840e332a09484c22b99f06dc0862f544c9b7428 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 26 Nov 2014 19:04:19 -0500 Subject: [PATCH 0596/1866] better template meta programming for are_same --- iterbase.hpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/iterbase.hpp b/iterbase.hpp index 76eee7b5..3e6f38d5 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace iter { // because std::advance assumes a lot and is actually smart, I need a dumb @@ -81,16 +82,12 @@ namespace iter { template - struct are_same { - constexpr static bool value = true; - }; + struct are_same : std::true_type { }; template - struct are_same { - constexpr static bool value = - std::is_same::value && are_same::value; - }; - + struct are_same + : std::integral_constant::value && are_same::value> { }; } #endif // #ifndef ITERBASE_HPP_ From 8ca26267972cb258f72e5ccaf95bf09860dd24f1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 4 Dec 2014 16:17:36 -0500 Subject: [PATCH 0597/1866] SConstruct gets whole environment --- catchtest/SConstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index e048c8b9..22f75cfb 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -1,7 +1,7 @@ import os env = Environment( - ENV = {'PATH' : os.environ['PATH']}, + ENV = os.environ, CXX='c++', CXXFLAGS= ['-g', '-Wall', '-Wextra', '-pedantic', '-std=c++11', From 7766143fe525836c56db91396aa242649ab3957c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 4 Dec 2014 16:17:51 -0500 Subject: [PATCH 0598/1866] SolidInt is non-movable and non-copyable --- catchtest/helpers.hpp | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/catchtest/helpers.hpp b/catchtest/helpers.hpp index 570373b0..bb034e16 100644 --- a/catchtest/helpers.hpp +++ b/catchtest/helpers.hpp @@ -5,11 +5,10 @@ namespace itertest { -// move-constructible only int wrapper +// non-copyable. non-movable. non-default-constructible class SolidInt { private: const int i; - bool made_from_move = false; public: constexpr SolidInt(int n) : i{n} @@ -23,17 +22,7 @@ class SolidInt { SolidInt(const SolidInt&) = delete; SolidInt& operator=(const SolidInt&) = delete; SolidInt& operator=(SolidInt&&) = delete; - - SolidInt(SolidInt&& other) - : i{other.i}, - made_from_move{true} - { - if (other.made_from_move) { - throw std::invalid_argument{ - "Object was constructed with a move ctor"}; - } - } - + SolidInt(SolidInt&&) = delete; }; From 886ceb09a21b791c77daa97b41cbb4f3e763664e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 4 Dec 2014 16:18:07 -0500 Subject: [PATCH 0599/1866] enumerate test builds SolidInts in place --- catchtest/test_enumerate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/catchtest/test_enumerate.cpp b/catchtest/test_enumerate.cpp index e9131fe5..b1b10474 100644 --- a/catchtest/test_enumerate.cpp +++ b/catchtest/test_enumerate.cpp @@ -102,7 +102,7 @@ TEST_CASE("Works with const iterable", "[enumerate]") { } TEST_CASE("Doesn't move or copy elements of iterable", "[enumerate]") { - constexpr SolidInt arr[] = {6, 7, 8}; + constexpr SolidInt arr[] = {{6}, {7}, {8}}; for (auto&& i : enumerate(arr)) { (void)i; } From 7dcd511a1b7a44efdbcf53b0e7a145430a064989 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 4 Dec 2014 16:18:21 -0500 Subject: [PATCH 0600/1866] zip test builds SolidInts in place --- catchtest/test_zip.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/catchtest/test_zip.cpp b/catchtest/test_zip.cpp index 1374feb1..785f7356 100644 --- a/catchtest/test_zip.cpp +++ b/catchtest/test_zip.cpp @@ -86,7 +86,7 @@ TEST_CASE("Can bind ref and move in single zip", "[zip]") { } TEST_CASE("zip doesn't move or copy elements of iterable", "[zip]") { - constexpr SolidInt arr[] = {6, 7, 8}; + constexpr SolidInt arr[] = {{6}, {7}, {8}}; for (auto&& t : zip(arr)) { (void)std::get<0>(t); } From c805865a3fc6ad1ebb6a697420145a52ebd36a35 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 4 Dec 2014 16:31:50 -0500 Subject: [PATCH 0601/1866] tests chain with non-movable --- catchtest/test_chain.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/catchtest/test_chain.cpp b/catchtest/test_chain.cpp index e01dbed5..d3b2cc94 100644 --- a/catchtest/test_chain.cpp +++ b/catchtest/test_chain.cpp @@ -1,3 +1,4 @@ +#include "helpers.hpp" #include #include @@ -10,6 +11,7 @@ #include "catch.hpp" using iter::chain; +using itertest::SolidInt; using Vec = const std::vector; TEST_CASE("chain three strings", "[chain]") { @@ -103,3 +105,10 @@ TEST_CASE("chain with only empty containers", "[chain]") { REQUIRE_FALSE( std::begin(ch) != std::end(ch) ); } } + +TEST_CASE("Chain doesn't move or copy elements of iterable", "[chain]") { + constexpr SolidInt arr[] = {{6}, {7}, {8}}; + for (auto&& i : chain(arr, arr)) { + (void)i; + } +} From 5dc3f014880732f2ddf44445c166d409545a4a89 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 4 Dec 2014 16:44:01 -0500 Subject: [PATCH 0602/1866] tests that chain moves and binds correctly --- catchtest/test_chain.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/catchtest/test_chain.cpp b/catchtest/test_chain.cpp index d3b2cc94..9d983a7f 100644 --- a/catchtest/test_chain.cpp +++ b/catchtest/test_chain.cpp @@ -12,6 +12,7 @@ using iter::chain; using itertest::SolidInt; +using itertest::BasicIterable; using Vec = const std::vector; TEST_CASE("chain three strings", "[chain]") { @@ -112,3 +113,18 @@ TEST_CASE("Chain doesn't move or copy elements of iterable", "[chain]") { (void)i; } } + +TEST_CASE("chain binds reference to lvalue and moves rvalue", "[chain]") { + BasicIterable bi{'x', 'y', 'z'}; + BasicIterable bi2{'a', 'j', 'm'}; + SECTION("First moved, second ref'd") { + chain(std::move(bi), bi2); + REQUIRE( bi.was_moved_from() ); + REQUIRE_FALSE( bi2.was_moved_from() ); + } + SECTION("First ref'd, second moved") { + chain(bi, std::move(bi2)); + REQUIRE_FALSE( bi.was_moved_from() ); + REQUIRE( bi2.was_moved_from() ); + } +} From f33d563f88ca025b28b399303d876deb0adc63ab Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 4 Dec 2014 23:58:26 -0500 Subject: [PATCH 0603/1866] combination iterator inherits from std::iterator --- combinations.hpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/combinations.hpp b/combinations.hpp index 2ae69dff..d5b877c1 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -1,5 +1,5 @@ -#ifndef COMBINATIONS_HPP_ -#define COMBINATIONS_HPP_ +#ifndef ITER_COMBINATIONS_HPP_ +#define ITER_COMBINATIONS_HPP_ #include "iterbase.hpp" @@ -35,9 +35,13 @@ namespace iter { length{in_length} { } + using CombIteratorDeref = + std::vector>; public: - class Iterator { + class Iterator : + public std::iterator + { private: Container& items; std::vector> indicies; @@ -66,8 +70,8 @@ namespace iter { } } - std::vector> operator*() { - std::vector> values; + CombIteratorDeref operator*() { + CombIteratorDeref values; for (auto i : indicies) { values.push_back(*i); } @@ -141,4 +145,4 @@ namespace iter { return {il, length}; } } -#endif //#ifndef COMBINATIONS_HPP_ +#endif From a5b60cc6bde696087af3a99eb0c53c674893ddd6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 4 Dec 2014 23:59:23 -0500 Subject: [PATCH 0604/1866] adds basic combination test --- catchtest/test_combinations.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 catchtest/test_combinations.cpp diff --git a/catchtest/test_combinations.cpp b/catchtest/test_combinations.cpp new file mode 100644 index 00000000..e2281d67 --- /dev/null +++ b/catchtest/test_combinations.cpp @@ -0,0 +1,27 @@ +#include "helpers.hpp" +#include + +#include +#include +#include +#include + +#include "catch.hpp" + + +using iter::combinations; +using CharCombSet = std::multiset>; + +TEST_CASE("Simple combination of 4", "[combinations]") { + std::string s = "ABCD"; + CharCombSet sc; + for (auto v : combinations(s, 2)) { + std::vector vcopy(std::begin(v), std::end(v)); + sc.insert(vcopy); + } + + CharCombSet ans = + {{'A','B'}, {'A','C'}, {'A','D'}, {'B','C'}, {'B','D'}, {'C','D'}}; + REQUIRE( ans == sc ); +} + From eca7189147afee5c8ea9e3c53194fe7c142b3c8b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 4 Dec 2014 23:59:32 -0500 Subject: [PATCH 0605/1866] builds combinations test --- catchtest/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index 22f75cfb..be2907b9 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -20,6 +20,7 @@ progs = Split( range accumulate chain + combinations ''' ) From a0168f27cd6ad7d7c34ebd06c34ac612a453071a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Dec 2014 18:52:42 -0500 Subject: [PATCH 0606/1866] tests enum postfix++ --- catchtest/test_enumerate.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/catchtest/test_enumerate.cpp b/catchtest/test_enumerate.cpp index b1b10474..ed8893e1 100644 --- a/catchtest/test_enumerate.cpp +++ b/catchtest/test_enumerate.cpp @@ -25,7 +25,7 @@ using iter::enumerate; using itertest::BasicIterable; using itertest::SolidInt; -TEST_CASE("Basic Function", "[enumerate]") { +TEST_CASE("Basic Functioning enumerate", "[enumerate]") { std::string str = "abc"; auto e = enumerate(str); Vec v(std::begin(e), std::end(e)); @@ -34,14 +34,21 @@ TEST_CASE("Basic Function", "[enumerate]") { REQUIRE( v == vc ); } -TEST_CASE("Empty", "[enumerate]") { +TEST_CASE("Empty enumerate", "[enumerate]") { std::string emp{}; auto e = enumerate(emp); - Vec v(std::begin(e), std::end(e)); + REQUIRE( std::begin(e) == std::end(e) ); +} - REQUIRE( v.empty() ); +TEST_CASE("Postfix ++ enumerate", "[enumerate]") { + std::string s{"amz"}; + auto e = enumerate(s); + auto it = std::begin(e); + it++; + REQUIRE( (*it).first == 2 ); } + TEST_CASE("Modifications through enumerate affect container", "[enumerate]") { std::vector v{1, 2, 3, 4}; std::vector vc(v.size(), -1); @@ -52,7 +59,7 @@ TEST_CASE("Modifications through enumerate affect container", "[enumerate]") { REQUIRE( v == vc ); } -TEST_CASE("Static array works", "[enumerate]") { +TEST_CASE("enumerate with static array works", "[enumerate]") { char arr[] = {'w', 'x', 'y'}; SECTION("Conversion to vector") { From 53fdfa86fb94748e8f502d4a7625c1272a2888b3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Dec 2014 18:53:34 -0500 Subject: [PATCH 0607/1866] adds enumerate == and postfix ++ --- enumerate.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/enumerate.hpp b/enumerate.hpp index 93592838..a3208cda 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -86,9 +86,19 @@ namespace 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() { From f28d2d8e452ad65e04bd85c85c4ce5b9e7307f35 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Dec 2014 19:30:56 -0500 Subject: [PATCH 0608/1866] tests zip postfix++ --- catchtest/test_zip.cpp | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/catchtest/test_zip.cpp b/catchtest/test_zip.cpp index 785f7356..ea16877c 100644 --- a/catchtest/test_zip.cpp +++ b/catchtest/test_zip.cpp @@ -16,7 +16,7 @@ using iter::zip; using itertest::BasicIterable; using itertest::SolidInt; -TEST_CASE("Simple case, same length", "[zip]") { +TEST_CASE("zip: Simple case, same length", "[zip]") { using Tu = std::tuple; using ResVec = const std::vector; std::vector iv {10, 20, 30}; @@ -29,7 +29,7 @@ TEST_CASE("Simple case, same length", "[zip]") { REQUIRE( v == vc ); } -TEST_CASE("One empty, all empty", "[zip]") { +TEST_CASE("zip: One empty, all empty", "[zip]") { std::vector iv = {1,2,3}; std::string s{}; auto z = zip(iv, s); @@ -38,7 +38,7 @@ TEST_CASE("One empty, all empty", "[zip]") { REQUIRE_FALSE( std::begin(z2) != std::end(z2) ); } -TEST_CASE("terminates on shortest sequence", "[zip]") { +TEST_CASE("zip: terminates on shortest sequence", "[zip]") { std::vector iv{1,2,3,4,5}; std::string s{"hi"}; auto z = zip(iv, s); @@ -46,12 +46,12 @@ TEST_CASE("terminates on shortest sequence", "[zip]") { REQUIRE( std::distance(std::begin(z), std::end(z)) == 2 ); } -TEST_CASE("Empty zip()", "[zip]") { +TEST_CASE("zip: Empty", "[zip]") { auto z = zip(); REQUIRE_FALSE( std::begin(z) != std::end(z) ); } -TEST_CASE("Modify sequence through zip", "[zip]") { +TEST_CASE("zip: Modify sequence through zip", "[zip]") { std::vector iv{1,2,3}; std::vector iv2{1,2,3,4}; for (auto&& t : zip(iv, iv2)) { @@ -65,19 +65,19 @@ TEST_CASE("Modify sequence through zip", "[zip]") { REQUIRE( iv2 == vc2); } -TEST_CASE("zip binds reference when it should", "[zip]") { +TEST_CASE("zip: binds reference when it should", "[zip]") { BasicIterable bi{'x', 'y', 'z'}; zip(bi); REQUIRE_FALSE( bi.was_moved_from() ); } -TEST_CASE("zip moves rvalues", "[zip]") { +TEST_CASE("zip: moves rvalues", "[zip]") { BasicIterable bi{'x', 'y', 'z'}; zip(std::move(bi)); REQUIRE( bi.was_moved_from() ); } -TEST_CASE("Can bind ref and move in single zip", "[zip]") { +TEST_CASE("zip: Can bind ref and move in single zip", "[zip]") { BasicIterable b1{'x', 'y', 'z'}; BasicIterable b2{'a', 'b'}; zip(b1, std::move(b2)); @@ -85,9 +85,17 @@ TEST_CASE("Can bind ref and move in single zip", "[zip]") { REQUIRE( b2.was_moved_from() ); } -TEST_CASE("zip doesn't move or copy elements of iterable", "[zip]") { +TEST_CASE("zip: doesn't move or copy elements of iterable", "[zip]") { constexpr SolidInt arr[] = {{6}, {7}, {8}}; for (auto&& t : zip(arr)) { (void)std::get<0>(t); } } + +TEST_CASE("zip: postfix ++", "[zip]") { + const std::vector v = {1}; + auto z = zip(v); + auto it = std::begin(z); + it++; + REQUIRE( !(it != std::end(z)) ); +} From ac4dd2c7bfc553d6863bf0057edf5f1262fbdf50 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Dec 2014 19:31:07 -0500 Subject: [PATCH 0609/1866] adds zip postfix++ --- zip.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/zip.hpp b/zip.hpp index cda4c5c4..60de9f39 100644 --- a/zip.hpp +++ b/zip.hpp @@ -59,6 +59,12 @@ namespace iter { return *this; } + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + bool operator!=(const Iterator& other) const { return this->iter != other.iter && (RestIter::is_base_iter || @@ -107,6 +113,10 @@ namespace iter { return *this; } + Iterator operator++(int) { + 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 From 98f17875812f382815e579d7003f8d78a045ac77 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Dec 2014 19:34:18 -0500 Subject: [PATCH 0610/1866] uses zip == instead of !(!=) --- catchtest/test_zip.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/catchtest/test_zip.cpp b/catchtest/test_zip.cpp index ea16877c..106c9444 100644 --- a/catchtest/test_zip.cpp +++ b/catchtest/test_zip.cpp @@ -97,5 +97,5 @@ TEST_CASE("zip: postfix ++", "[zip]") { auto z = zip(v); auto it = std::begin(z); it++; - REQUIRE( !(it != std::end(z)) ); + REQUIRE( it == std::end(z) ); } From 7af01fb49bee4975bf2d8377798710ab0d3d63f4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Dec 2014 19:34:31 -0500 Subject: [PATCH 0611/1866] adds zip == --- zip.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/zip.hpp b/zip.hpp index 60de9f39..1319254a 100644 --- a/zip.hpp +++ b/zip.hpp @@ -71,6 +71,10 @@ namespace iter { this->rest_iter != other.rest_iter); } + bool operator==(const Iterator& other) const { + return !(*this == other); + } + auto operator*() -> decltype(std::tuple_cat( std::tuple>{ @@ -126,6 +130,10 @@ namespace iter { return false; } + bool operator==(const Iterator& other) const { + return !(*this != other); + } + std::tuple<> operator*() { return std::tuple<>{}; } From 79f51631af95ae650b038c1ff9f174161c1d1df8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Dec 2014 19:44:25 -0500 Subject: [PATCH 0612/1866] uses range == in test --- catchtest/test_range.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/catchtest/test_range.cpp b/catchtest/test_range.cpp index 7c853595..94c51270 100644 --- a/catchtest/test_range.cpp +++ b/catchtest/test_range.cpp @@ -10,7 +10,7 @@ using Vec = const std::vector; using iter::range; -TEST_CASE("Range works with only stop", "[range]") { +TEST_CASE("range: works with only stop", "[range]") { auto r = range(5); Vec v(std::begin(r), std::end(r)); Vec vc{0, 1, 2, 3, 4}; @@ -18,7 +18,7 @@ TEST_CASE("Range works with only stop", "[range]") { REQUIRE( v == vc ); } -TEST_CASE("Range works with start and stop", "[range]") { +TEST_CASE("range: works with start and stop", "[range]") { auto r = range(1, 5); Vec v(std::begin(r), std::end(r)); Vec vc {1, 2, 3, 4}; @@ -26,7 +26,7 @@ TEST_CASE("Range works with start and stop", "[range]") { REQUIRE( v == vc ); } -TEST_CASE("Range works with positive step > 1", "[range]") { +TEST_CASE("range: works with positive step > 1", "[range]") { auto r = range(1, 10, 3); Vec v(std::begin(r), std::end(r)); Vec vc{1, 4, 7}; @@ -36,8 +36,7 @@ TEST_CASE("Range works with positive step > 1", "[range]") { TEST_CASE("range(0) is empty", "[range]") { auto r = iter::range(0); - Vec v(std::begin(r), std::end(r)); - REQUIRE( v.empty() ); + REQUIRE( std::begin(r) == std::end(r) ); } TEST_CASE("start > stop produces empty range", "[range]") { @@ -52,14 +51,14 @@ TEST_CASE("start < stop and step < 0 produces empty range", "[range]") { REQUIRE( v.empty() ); } -TEST_CASE("Range with only a negative stop is empty", "[range]") { +TEST_CASE("range: with only a negative stop is empty", "[range]") { auto r = range(-3); Vec v(std::begin(r), std::end(r)); REQUIRE( v.empty() ); } -TEST_CASE("Range works with negative step", "[range]") { +TEST_CASE("range: works with negative step", "[range]") { auto r = range(5, -5, -3); Vec v(std::begin(r), std::end(r)); Vec vc{5, 2, -1, -4}; @@ -67,7 +66,7 @@ TEST_CASE("Range works with negative step", "[range]") { REQUIRE( v == vc ); } -TEST_CASE("Range stops short when step doesn't divide stop-start", "[range]") { +TEST_CASE("range: stops short when step doesn't divide stop-start", "[range]") { auto r = range(0, 5, 2); Vec v(std::begin(r), std::end(r)); Vec vc{0, 2, 4}; @@ -76,7 +75,7 @@ TEST_CASE("Range stops short when step doesn't divide stop-start", "[range]") { } -TEST_CASE("Range stops short when step > stop-start", "[range]") { +TEST_CASE("range: stops short when step > stop-start", "[range]") { auto r = range(0, 10, 20); Vec v(std::begin(r), std::end(r)); REQUIRE( v.size() == 1 ); @@ -86,7 +85,7 @@ TEST_CASE("No 0 step ranges allowed", "[range]") { REQUIRE_THROWS(range(0, 1, 0)); } -TEST_CASE("Range works with a variable start, stop, and step", "[range]") { +TEST_CASE("range: works with a variable start, stop, and step", "[range]") { constexpr int a = 10; constexpr int b = 100; constexpr int c = 50; From c3e0cde6a81b7e530dc5216ffd6668e382d1ccd2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Dec 2014 19:44:38 -0500 Subject: [PATCH 0613/1866] adds == to range --- range.hpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/range.hpp b/range.hpp index f54de39f..c3cacab2 100644 --- a/range.hpp +++ b/range.hpp @@ -111,10 +111,18 @@ namespace iter { // 2) (stop - start) % step != 0. For // example Range(1, 10, 2). The iterator will never be // exactly equal to the stop value. + // + // Another way to think about it is that the "end" + // iterator represents the range of values that are invalid + // 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()); } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } }; Iterator begin() const { @@ -140,7 +148,7 @@ namespace iter { template Range range(T start, T stop, T step) { if (step == 0) { - throw RangeException(); + throw RangeException{}; } return {start, stop, step}; } From 37872c175f2cc0e939173bd2bd4811c31e4e516f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Dec 2014 19:47:44 -0500 Subject: [PATCH 0614/1866] tests for postfix ++ --- catchtest/test_range.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/catchtest/test_range.cpp b/catchtest/test_range.cpp index 94c51270..9a0bee9e 100644 --- a/catchtest/test_range.cpp +++ b/catchtest/test_range.cpp @@ -39,6 +39,13 @@ TEST_CASE("range(0) is empty", "[range]") { REQUIRE( std::begin(r) == std::end(r) ); } +TEST_CASE("range: postfix++", "[range]") { + auto r = iter::range(3); + auto it = std::begin(r); + it++; + REQUIRE( *it == 1 ); +} + TEST_CASE("start > stop produces empty range", "[range]") { auto r = range(5, 0); Vec v(std::begin(r), std::end(r)); From 63c7715c5ea8cec84b78d22982b6567b56ba3da4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Dec 2014 19:48:29 -0500 Subject: [PATCH 0615/1866] adds range postfix ++ --- range.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/range.hpp b/range.hpp index c3cacab2..6366e727 100644 --- a/range.hpp +++ b/range.hpp @@ -98,6 +98,12 @@ namespace iter { return *this; } + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + // This operator would more accurately read as "in bounds" // or "incomplete" because exact comparison with the end // isn't good enough for the purposes of this Iterator. From 3857d8b8316edaadebe7da2559225d1e38948d80 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Dec 2014 19:57:00 -0500 Subject: [PATCH 0616/1866] fixes enumerate test --- catchtest/test_enumerate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/catchtest/test_enumerate.cpp b/catchtest/test_enumerate.cpp index ed8893e1..6fb747b8 100644 --- a/catchtest/test_enumerate.cpp +++ b/catchtest/test_enumerate.cpp @@ -45,7 +45,7 @@ TEST_CASE("Postfix ++ enumerate", "[enumerate]") { auto e = enumerate(s); auto it = std::begin(e); it++; - REQUIRE( (*it).first == 2 ); + REQUIRE( (*it).first == 1 ); } From 5596909f0004bf2160cb0946d4f6129b13dfa5ff Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Dec 2014 19:57:59 -0500 Subject: [PATCH 0617/1866] tests accumulate == --- catchtest/test_accumulate.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/catchtest/test_accumulate.cpp b/catchtest/test_accumulate.cpp index a1cbf92e..00a9cd4e 100644 --- a/catchtest/test_accumulate.cpp +++ b/catchtest/test_accumulate.cpp @@ -20,7 +20,7 @@ TEST_CASE("Simple sum", "[accumulate]") { REQUIRE( v == vc ); } -TEST_CASE("With subtraction lambda", "[accumulate]") { +TEST_CASE("accumulate: With subtraction lambda", "[accumulate]") { Vec ns{5,4,3,2,1}; auto a = accumulate(ns, [](int a, int b){return a - b; }); @@ -29,7 +29,7 @@ TEST_CASE("With subtraction lambda", "[accumulate]") { REQUIRE( v == vc ); } -TEST_CASE("accumulate with initializer_list works", "[accumulate]") { +TEST_CASE("accumulate: with initializer_list works", "[accumulate]") { auto a = accumulate({1, 2, 3}); Vec v(std::begin(a), std::end(a)); Vec vc{1, 3, 6}; @@ -37,14 +37,20 @@ TEST_CASE("accumulate with initializer_list works", "[accumulate]") { REQUIRE( v == vc ); } -TEST_CASE("accumulate binds reference when it should", "[accumulate]") { +TEST_CASE("accumulate: binds reference when it should", "[accumulate]") { BasicIterable bi{1, 2}; accumulate(bi); REQUIRE_FALSE( bi.was_moved_from() ); } -TEST_CASE("moves rvalues into accumulator object", "[accumulate]") { +TEST_CASE("accumulate: moves rvalues when it should", "[accumulate]") { BasicIterable bi{1, 2}; accumulate(std::move(bi)); REQUIRE( bi.was_moved_from() ); } + +TEST_CASE("accumulate: operator==", "[accumulate]") { + std::vector v; + auto a = accumulate(v); + REQUIRE( std::begin(a) == std::end(a) ); +} From 60127da7362ee2acaf73b82e53f4b963cb4a7499 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Dec 2014 19:58:08 -0500 Subject: [PATCH 0618/1866] adds == to accumulate --- accumulate.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/accumulate.hpp b/accumulate.hpp index 013a6b2e..97619ac2 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -87,6 +87,10 @@ namespace iter { bool operator!=(const Iterator& other) const { return this->sub_iter != other.sub_iter; } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } }; Iterator begin() { From 86c1d59072ffadd3b8ae7279c3cc0adf9ecf5e81 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Dec 2014 20:00:52 -0500 Subject: [PATCH 0619/1866] tests accumulate postfix ++ --- catchtest/test_accumulate.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/catchtest/test_accumulate.cpp b/catchtest/test_accumulate.cpp index 00a9cd4e..7912d8d5 100644 --- a/catchtest/test_accumulate.cpp +++ b/catchtest/test_accumulate.cpp @@ -50,7 +50,16 @@ TEST_CASE("accumulate: moves rvalues when it should", "[accumulate]") { } TEST_CASE("accumulate: operator==", "[accumulate]") { - std::vector v; + Vec v; auto a = accumulate(v); REQUIRE( std::begin(a) == std::end(a) ); } + +TEST_CASE("accumulate: postfix ++", "[accumulate]") { + Vec ns{2,3}; + auto a = accumulate(ns); + auto it = std::begin(a); + it++; + REQUIRE( *it == 5 ); +} + From 9c32be51c13eb332ada95386a500b07eb384a06e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Dec 2014 20:01:01 -0500 Subject: [PATCH 0620/1866] adds accumulate postfix ++ --- accumulate.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/accumulate.hpp b/accumulate.hpp index 97619ac2..218c98cb 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -84,6 +84,12 @@ namespace 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; } From 8dfc5b1f38710ffd5a07fd185a51fe98f2a37e16 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Dec 2014 20:14:08 -0500 Subject: [PATCH 0621/1866] adds chain test for == --- catchtest/test_chain.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/catchtest/test_chain.cpp b/catchtest/test_chain.cpp index 9d983a7f..6ed0e365 100644 --- a/catchtest/test_chain.cpp +++ b/catchtest/test_chain.cpp @@ -15,7 +15,7 @@ using itertest::SolidInt; using itertest::BasicIterable; using Vec = const std::vector; -TEST_CASE("chain three strings", "[chain]") { +TEST_CASE("chain: three strings", "[chain]") { std::string s1{"abc"}; std::string s2{"mno"}; std::string s3{"xyz"}; @@ -27,7 +27,7 @@ TEST_CASE("chain three strings", "[chain]") { REQUIRE( v == vc ); } -TEST_CASE("chain with different container types", "[chain]") { +TEST_CASE("chain: with different container types", "[chain]") { std::string s1{"abc"}; std::list li{'m', 'n', 'o'}; std::vector vec{'x', 'y', 'z'}; @@ -39,7 +39,7 @@ TEST_CASE("chain with different container types", "[chain]") { REQUIRE( v == vc ); } -TEST_CASE("chain handles empty containers", "[chain]") { +TEST_CASE("chain: handles empty containers", "[chain]") { std::string emp; std::string a{"a"}; std::string b{"b"}; @@ -89,7 +89,7 @@ TEST_CASE("chain handles empty containers", "[chain]") { } } -TEST_CASE("chain with only empty containers", "[chain]") { +TEST_CASE("chain: with only empty containers", "[chain]") { std::string emp{}; SECTION("one empty container") { auto ch = chain(emp); @@ -107,14 +107,14 @@ TEST_CASE("chain with only empty containers", "[chain]") { } } -TEST_CASE("Chain doesn't move or copy elements of iterable", "[chain]") { +TEST_CASE("chain: doesn't move or copy elements of iterable", "[chain]") { constexpr SolidInt arr[] = {{6}, {7}, {8}}; for (auto&& i : chain(arr, arr)) { (void)i; } } -TEST_CASE("chain binds reference to lvalue and moves rvalue", "[chain]") { +TEST_CASE("chain: binds reference to lvalue and moves rvalue", "[chain]") { BasicIterable bi{'x', 'y', 'z'}; BasicIterable bi2{'a', 'j', 'm'}; SECTION("First moved, second ref'd") { @@ -128,3 +128,9 @@ TEST_CASE("chain binds reference to lvalue and moves rvalue", "[chain]") { REQUIRE( bi2.was_moved_from() ); } } + +TEST_CASE("chain: operator==", "[chain]") { + std::string emp{}; + auto ch = chain(emp); + REQUIRE( std::begin(ch) == std::end(ch) ); +} From 3b381e32dd4fc8dc5349a2e3405aa7653115d177 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Dec 2014 20:14:20 -0500 Subject: [PATCH 0622/1866] adds chain == --- chain.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/chain.hpp b/chain.hpp index 5029a9df..ae086782 100644 --- a/chain.hpp +++ b/chain.hpp @@ -78,6 +78,10 @@ namespace iter { this->rest_iter != other.rest_iter; } + bool operator==(const Iterator& other) const { + return !(*this != other); + } + iterator_deref operator*() { return this->at_end ? *this->rest_iter : *this->sub_iter; @@ -136,6 +140,10 @@ namespace iter { return this->sub_iter != other.sub_iter; } + bool operator==(const Iterator& other) const { + return !(*this != other); + } + iterator_deref operator*() { return *this->sub_iter; } @@ -206,6 +214,10 @@ namespace iter { *this->sub_iter_p != *other.sub_iter_p); } + bool operator==(const Iterator& other) const { + return !(*this != other); + } + iterator_deref> operator*() { return **this->sub_iter_p; } From 7324e54203355cf82093aa82e1c2638b1e1acd2e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Dec 2014 20:18:23 -0500 Subject: [PATCH 0623/1866] tests chain postfix ++ --- catchtest/test_chain.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/catchtest/test_chain.cpp b/catchtest/test_chain.cpp index 6ed0e365..05a9b165 100644 --- a/catchtest/test_chain.cpp +++ b/catchtest/test_chain.cpp @@ -134,3 +134,12 @@ TEST_CASE("chain: operator==", "[chain]") { auto ch = chain(emp); REQUIRE( std::begin(ch) == std::end(ch) ); } + +TEST_CASE("chain: postfix ++", "[chain]") { + std::string s1{"a"}, s2{"b"}; + auto ch = chain(s1, s2); + auto it = std::begin(ch); + it++; + REQUIRE( *it == 'b'); +} + From 8b629b7aeb1140f3cb6190f4e53276fa9c56357c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Dec 2014 20:18:35 -0500 Subject: [PATCH 0624/1866] adds chain postfix ++ --- chain.hpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/chain.hpp b/chain.hpp index ae086782..4e74a95b 100644 --- a/chain.hpp +++ b/chain.hpp @@ -73,6 +73,12 @@ namespace 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 || this->rest_iter != other.rest_iter; @@ -136,6 +142,12 @@ namespace 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; } @@ -206,7 +218,13 @@ namespace iter { } return *this; } - + + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } bool operator!=(const Iterator& other) const { return this->top_level_iter != other.top_level_iter && From 610c7bdd15e15513daced8f81e375b53053499ee Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Dec 2014 21:13:17 -0500 Subject: [PATCH 0625/1866] adds iterator_traits_deref Gives the type returned from dereferencing an iterator with any references removed. --- iterbase.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iterbase.hpp b/iterbase.hpp index 3e6f38d5..0ce5d441 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -56,6 +56,10 @@ namespace iter { using iterator_deref = decltype(*std::declval&>()); + template + using iterator_traits_deref = + typename std::remove_reference>::type; + // iterator_type is the type of C's iterator template using reverse_iterator_type = From 7cae42e3e0e016d316ca75a2584b41e049126d58 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Dec 2014 21:14:12 -0500 Subject: [PATCH 0626/1866] adds chain.from_iterable basic test --- catchtest/test_chain.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/catchtest/test_chain.cpp b/catchtest/test_chain.cpp index 05a9b165..a5651b6a 100644 --- a/catchtest/test_chain.cpp +++ b/catchtest/test_chain.cpp @@ -143,3 +143,12 @@ TEST_CASE("chain: postfix ++", "[chain]") { REQUIRE( *it == 'b'); } + +TEST_CASE("chain.from_iterable: basic test", "chain.from_iterable") { + std::vector sv{"abc", "xyz"}; + auto ch = chain.from_iterable(sv); + std::vector v(std::begin(ch), std::end(ch)); + + std::vector vc{'a', 'b', 'c', 'x', 'y', 'z'}; + REQUIRE( v == vc ); +} From bcb726b9284464366a01520ae6fd4d3748365c29 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Dec 2014 21:14:50 -0500 Subject: [PATCH 0627/1866] Makes chain iterator copy constructible also uses the iterbase iterator_traits_deref --- chain.hpp | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/chain.hpp b/chain.hpp index 4e74a95b..addb041c 100644 --- a/chain.hpp +++ b/chain.hpp @@ -27,9 +27,6 @@ namespace iter { template friend class Chained; - using iter_traits_deref = - typename std::remove_reference>::type; - private: Container container; Chained rest_chained; @@ -41,7 +38,8 @@ namespace iter { public: class Iterator : public std::iterator< - std::input_iterator_tag, iter_traits_deref> + std::input_iterator_tag, + iterator_traits_deref> { private: using RestIter = @@ -112,9 +110,6 @@ namespace iter { template friend class Chained; - using iter_traits_deref = - typename std::remove_reference>::type; - private: Container container; Chained(Container container) @@ -124,7 +119,8 @@ namespace iter { public: class Iterator : public std::iterator< - std::input_iterator_tag, iter_traits_deref> + std::input_iterator_tag, + iterator_traits_deref> { private: iterator_type sub_iter; @@ -182,7 +178,10 @@ namespace iter { { } public: - class Iterator { + class Iterator + :public std::iterator>> + { private: using SubContainer = iterator_deref; using SubIter = iterator_type; @@ -202,6 +201,15 @@ namespace iter { nullptr : new SubIter{std::end(*top_iter)}} { } + Iterator(const Iterator& other) + : top_level_iter{other.top_level_iter}, + top_level_end{other.top_level_end}, + sub_iter_p{other.sub_iter_p ? + new SubIter{*other.sub_iter_p} : nullptr}, + sub_end_p{other.sub_end_p ? + new SubIter{*other.sub_end_p} : nullptr} + { } + Iterator& operator++() { ++*this->sub_iter_p; if (!(*this->sub_iter_p != *this->sub_end_p)) { From ebb1cf5bebc7e68e1f01c8add327dfec88ea523a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Dec 2014 23:19:10 -0500 Subject: [PATCH 0628/1866] tests chain.from_iterable more --- catchtest/test_chain.cpp | 43 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/catchtest/test_chain.cpp b/catchtest/test_chain.cpp index a5651b6a..19655c81 100644 --- a/catchtest/test_chain.cpp +++ b/catchtest/test_chain.cpp @@ -144,7 +144,7 @@ TEST_CASE("chain: postfix ++", "[chain]") { } -TEST_CASE("chain.from_iterable: basic test", "chain.from_iterable") { +TEST_CASE("chain.from_iterable: basic test", "[chain.from_iterable]") { std::vector sv{"abc", "xyz"}; auto ch = chain.from_iterable(sv); std::vector v(std::begin(ch), std::end(ch)); @@ -152,3 +152,44 @@ TEST_CASE("chain.from_iterable: basic test", "chain.from_iterable") { std::vector vc{'a', 'b', 'c', 'x', 'y', 'z'}; REQUIRE( v == vc ); } + +TEST_CASE("chain.from_iterable: iterators cant be copy constructed " + "and assigned", "[chain.from_iterable]") { + std::vector sv{"abc", "xyz"}; + auto ch = chain.from_iterable(sv); + auto it = std::begin(ch); + + SECTION("Copy constructed") { + auto it2 = it; + ++it; + REQUIRE( it != it2 ); + } + + SECTION("Copy assigned") { + auto it2 = std::end(ch); + it2 = it; + REQUIRE( it == it2 ); + } +} + +TEST_CASE("chain.from_iterable: postfix ++", "[chain.from_iterable]") { + std::vector sv{"a", "n"}; + auto ch = chain.from_iterable(sv); + auto it = std::begin(ch); + it++; + REQUIRE( *it == 'n' ); +} + + +TEST_CASE("chain.from_iterable: moves rvalues and binds ref to lvalues", + "[chain.from_iterable]") { + BasicIterable bi{"abc", "xyz"}; + SECTION("Moves rvalue") { + chain.from_iterable(std::move(bi)); + REQUIRE( bi.was_moved_from() ); + } + SECTION("Binds ref to lvalue") { + chain.from_iterable(bi); + REQUIRE_FALSE( bi.was_moved_from() ); + } +} From 29e89e4689ae033058ab6ce12bdfe694d92bfcc5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Dec 2014 23:19:17 -0500 Subject: [PATCH 0629/1866] completes chain.from_iterable iterators --- chain.hpp | 50 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/chain.hpp b/chain.hpp index addb041c..399ea3e9 100644 --- a/chain.hpp +++ b/chain.hpp @@ -187,9 +187,29 @@ namespace iter { using SubIter = iterator_type; iterator_type top_level_iter; - const iterator_type top_level_end; + iterator_type top_level_end; std::unique_ptr sub_iter_p; std::unique_ptr sub_end_p; + + static std::unique_ptr clone_sub_pointer( + const SubIter* sub_iter) { + return std::unique_ptr{ sub_iter ? + new SubIter{*sub_iter} : nullptr}; + } + + bool sub_iters_differ(const Iterator& other) const { + if (this->sub_iter_p == other.sub_iter_p) { + return false; + } + if (this->sub_iter_p == nullptr + || other.sub_iter_p == nullptr) { + // since the first check tests if they're the same, + // this will return if only one is nullptr + return true; + } + return *this->sub_iter_p != *other.sub_iter_p; + } + public: Iterator(iterator_type top_iter, iterator_type top_end) @@ -204,12 +224,27 @@ namespace iter { Iterator(const Iterator& other) : top_level_iter{other.top_level_iter}, top_level_end{other.top_level_end}, - sub_iter_p{other.sub_iter_p ? - new SubIter{*other.sub_iter_p} : nullptr}, - sub_end_p{other.sub_end_p ? - new SubIter{*other.sub_end_p} : nullptr} + sub_iter_p{clone_sub_pointer(other.sub_iter_p.get())}, + sub_end_p{clone_sub_pointer(other.sub_end_p.get())} { } + Iterator& operator=(const Iterator& other) { + if (this == &other) return *this; + + this->top_level_iter = other.top_level_iter; + this->top_level_end = other.top_level_end; + this->sub_iter_p = + clone_sub_pointer(other.sub_iter_p.get()); + this->sub_end_p = + clone_sub_pointer(other.sub_end_p.get()); + + return *this; + } + + Iterator(Iterator&&) = default; + Iterator& operator=(Iterator&&) = default; + ~Iterator() = default; + Iterator& operator++() { ++*this->sub_iter_p; if (!(*this->sub_iter_p != *this->sub_end_p)) { @@ -235,9 +270,8 @@ namespace iter { } bool operator!=(const Iterator& other) const { - return this->top_level_iter != other.top_level_iter && - (this->sub_iter_p != other.sub_iter_p || - *this->sub_iter_p != *other.sub_iter_p); + return this->top_level_iter != other.top_level_iter + || this->sub_iters_differ(other); } bool operator==(const Iterator& other) const { From b0a34e8ec402b1ce1389c26a7b56dd07c807f9a9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 6 Dec 2014 01:02:26 -0500 Subject: [PATCH 0630/1866] tests chain with empty chain --- catchtest/test_chain.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/catchtest/test_chain.cpp b/catchtest/test_chain.cpp index 19655c81..23aa98f4 100644 --- a/catchtest/test_chain.cpp +++ b/catchtest/test_chain.cpp @@ -193,3 +193,9 @@ TEST_CASE("chain.from_iterable: moves rvalues and binds ref to lvalues", REQUIRE_FALSE( bi.was_moved_from() ); } } + +TEST_CASE("chain.from_iterable: empty", "[empty]") { + const std::vector v{}; + auto ch = chain.from_iterable(v); + REQUIRE( std::begin(ch) == std::end(ch) ); +} From 3302daca1a9a285c1ce4994dd50b7483f063f746 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 6 Dec 2014 01:04:02 -0500 Subject: [PATCH 0631/1866] fixes recursive == in zip --- zip.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zip.hpp b/zip.hpp index 1319254a..a77061bf 100644 --- a/zip.hpp +++ b/zip.hpp @@ -72,7 +72,7 @@ namespace iter { } bool operator==(const Iterator& other) const { - return !(*this == other); + return !(*this != other); } auto operator*() -> From 38121285798f169c2a3b264712bac8740ebbc248 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 6 Dec 2014 01:11:50 -0500 Subject: [PATCH 0632/1866] Adds combinations test where length is too big --- catchtest/test_combinations.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/catchtest/test_combinations.cpp b/catchtest/test_combinations.cpp index e2281d67..5f0b7b7d 100644 --- a/catchtest/test_combinations.cpp +++ b/catchtest/test_combinations.cpp @@ -12,8 +12,8 @@ using iter::combinations; using CharCombSet = std::multiset>; -TEST_CASE("Simple combination of 4", "[combinations]") { - std::string s = "ABCD"; +TEST_CASE("combinations: Simple combination of 4", "[combinations]") { + std::string s{"ABCD"}; CharCombSet sc; for (auto v : combinations(s, 2)) { std::vector vcopy(std::begin(v), std::end(v)); @@ -24,4 +24,9 @@ TEST_CASE("Simple combination of 4", "[combinations]") { {{'A','B'}, {'A','C'}, {'A','D'}, {'B','C'}, {'B','D'}, {'C','D'}}; REQUIRE( ans == sc ); } - + +TEST_CASE("combinations: size too large gives no results", "[combinations]") { + std::string s{"ABCD"}; + auto c = combinations(s, 5); + REQUIRE( !(std::begin(c) != std::end(c)) ); +} From 3402bd19cc2fa366f1413db6fd953c3a6461f5b5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 6 Dec 2014 18:15:52 -0500 Subject: [PATCH 0633/1866] marks combinations operator!= as const --- combinations.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/combinations.hpp b/combinations.hpp index d5b877c1..c828a4ed 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -114,8 +114,7 @@ namespace iter { return *this; } - bool operator !=(const Iterator&) - { + bool operator!=(const Iterator&) const { //because of the way this is done you have to start from //the begining of the range and end at the end, you could //break in the middle of the loop though, it's not From 810cb0796e6523b69daa96dd3d02a93e57a73a72 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 6 Dec 2014 18:18:53 -0500 Subject: [PATCH 0634/1866] adds combinations operator== --- combinations.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/combinations.hpp b/combinations.hpp index c828a4ed..c9f65587 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -121,6 +121,10 @@ namespace iter { //different from the way that python's works return not_done; } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } }; Iterator begin() { From 2307e4e3090fa3a09d369a52a2f382e644c2ef07 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 6 Dec 2014 18:19:16 -0500 Subject: [PATCH 0635/1866] uses == for combinations instead of !(!=) --- catchtest/test_combinations.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/catchtest/test_combinations.cpp b/catchtest/test_combinations.cpp index 5f0b7b7d..11f8cbb3 100644 --- a/catchtest/test_combinations.cpp +++ b/catchtest/test_combinations.cpp @@ -28,5 +28,11 @@ TEST_CASE("combinations: Simple combination of 4", "[combinations]") { TEST_CASE("combinations: size too large gives no results", "[combinations]") { std::string s{"ABCD"}; auto c = combinations(s, 5); - REQUIRE( !(std::begin(c) != std::end(c)) ); + REQUIRE( std::begin(c) == std::end(c) ); +} + +TEST_CASE("combinations: size 0 gives nothing", "[combinations]") { + std::string s{"ABCD"}; + auto c = combinations(s, 0); + REQUIRE( std::begin(c) == std::end(c) ); } From 5f2dcae76a7ee944b01f145a9c4e5c2fb034b360 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 6 Dec 2014 18:23:56 -0500 Subject: [PATCH 0636/1866] adds combinations postfix ++ --- combinations.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/combinations.hpp b/combinations.hpp index c9f65587..e05fb957 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -114,6 +114,12 @@ namespace iter { return *this; } + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + bool operator!=(const Iterator&) const { //because of the way this is done you have to start from //the begining of the range and end at the end, you could From 73b12b21b1fd40de7cb0e61226f455457899994e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 9 Dec 2014 20:18:17 -0500 Subject: [PATCH 0637/1866] tests correct movement and bind --- catchtest/test_combinations.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/catchtest/test_combinations.cpp b/catchtest/test_combinations.cpp index 11f8cbb3..d22db349 100644 --- a/catchtest/test_combinations.cpp +++ b/catchtest/test_combinations.cpp @@ -10,6 +10,7 @@ using iter::combinations; +using itertest::BasicIterable; using CharCombSet = std::multiset>; TEST_CASE("combinations: Simple combination of 4", "[combinations]") { @@ -36,3 +37,16 @@ TEST_CASE("combinations: size 0 gives nothing", "[combinations]") { auto c = combinations(s, 0); REQUIRE( std::begin(c) == std::end(c) ); } + +TEST_CASE("combinations: binds to lvalues, moves rvalues", "[combinations]") { + BasicIterable bi{'x', 'y', 'z'}; + SECTION("binds to lvalues") { + combinations(bi, 1); + REQUIRE_FALSE( bi.was_moved_from() ); + } + SECTION("moves rvalues") { + combinations(std::move(bi), 1); + REQUIRE( bi.was_moved_from() ); + } +} + From 3cd170a7d3a0e58636d68f97c24b7b097169f512 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 9 Dec 2014 21:19:41 -0500 Subject: [PATCH 0638/1866] Adds test for combinations with replacement --- .../test_combinations_with_replacement.cpp | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 catchtest/test_combinations_with_replacement.cpp diff --git a/catchtest/test_combinations_with_replacement.cpp b/catchtest/test_combinations_with_replacement.cpp new file mode 100644 index 00000000..bc5cd9ef --- /dev/null +++ b/catchtest/test_combinations_with_replacement.cpp @@ -0,0 +1,42 @@ +#include + +#include +#include +#include +#include + +#include "helpers.hpp" +#include "catch.hpp" + +using iter::combinations_with_replacement; +using itertest::BasicIterable; +using CharCombSet = std::multiset>; + +TEST_CASE("combinations_with_replacement: Simple combination", + "[combinations_with_replacement]") { + std::string s{"ABC"}; + CharCombSet sc; + for (auto v : combinations_with_replacement(s, 2)) { + std::vector vcopy(std::begin(v), std::end(v)); + sc.insert(vcopy); + } + CharCombSet ans = + {{'A','A'}, {'A','B'}, {'A','C'}, {'B','B'}, {'B','C'}, {'C','C'}}; + REQUIRE( ans == sc ); +} + + + +TEST_CASE("combinations_with_replacement: big size is no problem", + "[combinations_with_replacement]") { + std::string s{"AB"}; + CharCombSet sc; + for (auto v : combinations_with_replacement(s, 3)) { + std::vector vcopy(std::begin(v), std::end(v)); + sc.insert(vcopy); + } + CharCombSet ans = + {{'A', 'A', 'A'}, {'A', 'A', 'B'}, {'A', 'B', 'B'}, {'B', 'B', 'B'}}; + REQUIRE( ans == sc ); +} + From 10ebc700c0cb1de70e3d7efef967dfae194508c5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 9 Dec 2014 21:19:55 -0500 Subject: [PATCH 0639/1866] comb w/ repl iterator interits from std::iterator --- combinations_with_replacement.hpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index ead4319a..57f55bc7 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -41,8 +41,14 @@ namespace iter { length{n} { } + using CombIteratorDeref = + std::vector>; + public: - class Iterator { + class Iterator : + public std::iterator + { private: Container& items; std::vector> indicies; @@ -56,7 +62,7 @@ namespace iter { not_done{n != 0} { } - std::vector> operator*() { + CombIteratorDeref operator*() { std::vector> values; for (auto i : indicies) { values.push_back(*i); From 702797c7d1f53acf8922edfd74a0945cee31cfdc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 9 Dec 2014 21:20:44 -0500 Subject: [PATCH 0640/1866] tells scons to build comb w/ replacement test --- catchtest/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index be2907b9..bb00e117 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -21,6 +21,7 @@ progs = Split( accumulate chain combinations + combinations_with_replacement ''' ) From eed3c11764082aaf6cb1aa1c2cd491523c0ef630 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 9 Dec 2014 21:33:48 -0500 Subject: [PATCH 0641/1866] Tests odd sizes in comb w/ repl --- catchtest/test_combinations_with_replacement.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/catchtest/test_combinations_with_replacement.cpp b/catchtest/test_combinations_with_replacement.cpp index bc5cd9ef..1896d19e 100644 --- a/catchtest/test_combinations_with_replacement.cpp +++ b/catchtest/test_combinations_with_replacement.cpp @@ -40,3 +40,10 @@ TEST_CASE("combinations_with_replacement: big size is no problem", REQUIRE( ans == sc ); } +TEST_CASE("combinations_with_replacement: 0 size is empty", + "[combinations_with_replacement]") { + std::string s{"A"}; + auto cwr = combinations_with_replacement(s, 0); + REQUIRE( std::begin(cwr) == std::end(cwr) ); +} + From 585b130fb065380c33db95a933526dd9701f414e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 9 Dec 2014 21:34:06 -0500 Subject: [PATCH 0642/1866] Adds ++ and == to comb w/ repl iterator --- combinations_with_replacement.hpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index 57f55bc7..615da8b8 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -1,5 +1,5 @@ -#ifndef COMBINATIONS_WITH_REPLACEMENT_HPP_ -#define COMBINATIONS_WITH_REPLACEMENT_HPP_ +#ifndef ITER_COMBINATIONS_WITH_REPLACEMENT_HPP_ +#define ITER_COMBINATIONS_WITH_REPLACEMENT_HPP_ #include "iterbase.hpp" @@ -96,13 +96,25 @@ namespace iter { return *this; } - bool operator !=(const Iterator&) const { + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + bool operator!=(const Iterator&) const { //because of the way this is done you have to start from //the begining of the range and end at the end, you //could break in the middle of the loop though, it's not - //different from the waythat python's works + //different from the way that python's works return not_done; } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } + }; Iterator begin() { @@ -128,4 +140,4 @@ namespace iter { } } -#endif // #ifndef COMBINATIONS_WITH_REPLACEMENT_HPP_ +#endif From 49669cb41c31312b5048409fb82c12b133f5f778 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 11 Dec 2014 19:53:18 -0500 Subject: [PATCH 0643/1866] adds solidint test for combinations --- catchtest/test_combinations.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/catchtest/test_combinations.cpp b/catchtest/test_combinations.cpp index d22db349..c366cdba 100644 --- a/catchtest/test_combinations.cpp +++ b/catchtest/test_combinations.cpp @@ -11,6 +11,7 @@ using iter::combinations; using itertest::BasicIterable; +using itertest::SolidInt; using CharCombSet = std::multiset>; TEST_CASE("combinations: Simple combination of 4", "[combinations]") { @@ -50,3 +51,10 @@ TEST_CASE("combinations: binds to lvalues, moves rvalues", "[combinations]") { } } +TEST_CASE("combinations: doesn't move or copy elements of iterable", + "[combinations]") { + constexpr SolidInt arr[] = {{6}, {7}, {8}}; + for (auto&& i : combinations(arr, 1)) { + (void)i; + } +} From 3177132b5c3d5b49f353121ac65123bb426fa956 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 11 Dec 2014 19:56:47 -0500 Subject: [PATCH 0644/1866] tests comb w/ repl with solidint --- catchtest/test_combinations_with_replacement.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/catchtest/test_combinations_with_replacement.cpp b/catchtest/test_combinations_with_replacement.cpp index 1896d19e..6677009e 100644 --- a/catchtest/test_combinations_with_replacement.cpp +++ b/catchtest/test_combinations_with_replacement.cpp @@ -47,3 +47,11 @@ TEST_CASE("combinations_with_replacement: 0 size is empty", REQUIRE( std::begin(cwr) == std::end(cwr) ); } + +TEST_CASE("combinations_with_replacement: doesn't move or copy elements of iterable", + "[combinations_with_replacement]") { + constexpr itertest::SolidInt arr[] = {{6}, {7}, {8}}; + for (auto&& i : combinations_with_replacement(arr, 1)) { + (void)i; + } +} From 8df4eb77b08e24a284ea817a4396691499efca1b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 11 Dec 2014 20:50:04 -0500 Subject: [PATCH 0645/1866] adds basic compress test --- catchtest/test_compress.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 catchtest/test_compress.cpp diff --git a/catchtest/test_compress.cpp b/catchtest/test_compress.cpp new file mode 100644 index 00000000..78c45a17 --- /dev/null +++ b/catchtest/test_compress.cpp @@ -0,0 +1,26 @@ +#include "helpers.hpp" +#include + +#include +#include +#include +#include +#include +#include + +#include "catch.hpp" + +using iter::compress; +using itertest::SolidInt; +using itertest::BasicIterable; +using Vec = const std::vector; + +TEST_CASE("compress: alternating", "[compress]") { + std::vector ivec{1, 2, 3, 4, 5, 6}; + std::vector bvec{true, false, true, false, true, false}; + auto c = compress(ivec, bvec); + Vec v(std::begin(c), std::end(c)); + Vec vc = {1,3,5}; + + REQUIRE( v == vc ); +} From 996154aa4f87165586362fb4923c048aa4ffa9c9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 11 Dec 2014 20:50:41 -0500 Subject: [PATCH 0646/1866] compress iter derives std iterator --- compress.hpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/compress.hpp b/compress.hpp index 94dff629..fe5e0ea7 100644 --- a/compress.hpp +++ b/compress.hpp @@ -1,9 +1,10 @@ -#ifndef COMPRESS__H__ -#define COMPRESS__H__ +#ifndef ITER_COMPRESS_H_ +#define ITER_COMPRESS_H_ #include "iterbase.hpp" #include +#include #include namespace iter { @@ -65,7 +66,10 @@ namespace iter { public: Compressed(const Compressed&) = default; - class Iterator { + class Iterator + : public std::iterator> + { private: iterator_type sub_iter; const iterator_type sub_end; @@ -87,10 +91,10 @@ namespace iter { } public: - Iterator (iterator_type cont_iter, - iterator_type cont_end, - selector_iter_type sel_iter, - selector_iter_type sel_end) + Iterator(iterator_type cont_iter, + iterator_type cont_end, + selector_iter_type sel_iter, + selector_iter_type sel_end) : sub_iter{cont_iter}, sub_end{cont_end}, selector_iter{sel_iter}, @@ -158,4 +162,4 @@ namespace iter { } } -#endif //ifndef COMPRESS__H__ +#endif From 552901063b31d85993ea415bdd3014d795550a76 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 11 Dec 2014 20:50:57 -0500 Subject: [PATCH 0647/1866] adds true and false run tests for compress --- catchtest/SConstruct | 1 + catchtest/test_compress.cpp | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index bb00e117..4e5637e7 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -22,6 +22,7 @@ progs = Split( chain combinations combinations_with_replacement + compress ''' ) diff --git a/catchtest/test_compress.cpp b/catchtest/test_compress.cpp index 78c45a17..aac35c7b 100644 --- a/catchtest/test_compress.cpp +++ b/catchtest/test_compress.cpp @@ -24,3 +24,23 @@ TEST_CASE("compress: alternating", "[compress]") { REQUIRE( v == vc ); } + +TEST_CASE("compress: consecutive falses", "[compress]") { + std::vector ivec{1, 2, 3, 4, 5}; + std::vector bvec{true, false, false, false, true}; + auto c = compress(ivec, bvec); + Vec v(std::begin(c), std::end(c)); + Vec vc = {1,5}; + + REQUIRE( v == vc ); +} + +TEST_CASE("compress: consecutive trues", "[compress]") { + std::vector ivec{1, 2, 3, 4, 5}; + std::vector bvec{false, true, true, true, false}; + auto c = compress(ivec, bvec); + Vec v(std::begin(c), std::end(c)); + Vec vc = {2,3,4} + + REQUIRE( v == vc ); +} From abc71e39f2fcfce47f43f1239ecd30fe31e59605 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 11 Dec 2014 21:39:55 -0500 Subject: [PATCH 0648/1866] tests compress with all true --- catchtest/test_compress.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/catchtest/test_compress.cpp b/catchtest/test_compress.cpp index aac35c7b..468fd65d 100644 --- a/catchtest/test_compress.cpp +++ b/catchtest/test_compress.cpp @@ -13,7 +13,7 @@ using iter::compress; using itertest::SolidInt; using itertest::BasicIterable; -using Vec = const std::vector; +using Vec = const std::vector; TEST_CASE("compress: alternating", "[compress]") { std::vector ivec{1, 2, 3, 4, 5, 6}; @@ -40,7 +40,18 @@ TEST_CASE("compress: consecutive trues", "[compress]") { std::vector bvec{false, true, true, true, false}; auto c = compress(ivec, bvec); Vec v(std::begin(c), std::end(c)); - Vec vc = {2,3,4} + Vec vc = {2,3,4}; REQUIRE( v == vc ); } + +TEST_CASE("compress: all true", "[compress]") { + std::vector ivec{1, 2, 3, 4, 5}; + std::vector bvec(ivec.size(), true); + auto c = compress(ivec, bvec); + Vec v(std::begin(c), std::end(c)); + + REQUIRE( v == ivec ); +} + + From 0ef255d023c41cfa474920097b1a883ecd30d0bd Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 11 Dec 2014 21:48:32 -0500 Subject: [PATCH 0649/1866] compress with all false --- catchtest/test_compress.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/catchtest/test_compress.cpp b/catchtest/test_compress.cpp index 468fd65d..7dfdedc8 100644 --- a/catchtest/test_compress.cpp +++ b/catchtest/test_compress.cpp @@ -54,4 +54,10 @@ TEST_CASE("compress: all true", "[compress]") { REQUIRE( v == ivec ); } +TEST_CASE("compress: all false", "[compress]") { + std::vector ivec{1, 2, 3, 4, 5}; + std::vector bvec(ivec.size(), false); + auto c = compress(ivec, bvec); + REQUIRE( std::begin(c) == std::end(c) ); +} From c88a2b778822988321779c2bd2a6aada2c3ef04c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 11 Dec 2014 21:48:38 -0500 Subject: [PATCH 0650/1866] adds == for compress iter --- compress.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compress.hpp b/compress.hpp index fe5e0ea7..2af0668a 100644 --- a/compress.hpp +++ b/compress.hpp @@ -117,6 +117,10 @@ namespace iter { return this->sub_iter != other.sub_iter && this->selector_iter != other.selector_iter; } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } }; Iterator begin() { From b4a9bb8a03ee65fdb1af8a85323dc70f63981a5a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 11 Dec 2014 21:49:43 -0500 Subject: [PATCH 0651/1866] adds compress iter ++ and removes ctor specs I needn't specify the deletes and defaults, it doesn't gain me anything --- compress.hpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compress.hpp b/compress.hpp index 2af0668a..9d3ff7d0 100644 --- a/compress.hpp +++ b/compress.hpp @@ -60,11 +60,8 @@ namespace iter { : container(std::forward(container)), selectors(std::forward(selectors)) { } - Compressed() = delete; - Compressed& operator=(const Compressed&) = delete; public: - Compressed(const Compressed&) = default; class Iterator : public std::iteratorsub_iter != other.sub_iter && this->selector_iter != other.selector_iter; From 17cd4b6c5fb6eb1626c7891f28fdecdb5151a954 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 11 Dec 2014 21:52:01 -0500 Subject: [PATCH 0652/1866] tests that compress moves and binds correctly --- catchtest/test_compress.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/catchtest/test_compress.cpp b/catchtest/test_compress.cpp index 7dfdedc8..6050ca05 100644 --- a/catchtest/test_compress.cpp +++ b/catchtest/test_compress.cpp @@ -61,3 +61,15 @@ TEST_CASE("compress: all false", "[compress]") { REQUIRE( std::begin(c) == std::end(c) ); } +TEST_CASE("compress: binds to lvalues, moves rvalues", "[compress]") { + BasicIterable bi{'x', 'y', 'z'}; + std::vector bl{true, true, true}; + SECTION("binds to lvalues") { + compress(bi, bl); + REQUIRE_FALSE( bi.was_moved_from() ); + } + SECTION("moves rvalues") { + compress(std::move(bi), bl); + REQUIRE( bi.was_moved_from() ); + } +} From f36f405bbc79e0d2c57269699a5fa90796fbea29 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 11 Dec 2014 22:03:01 -0500 Subject: [PATCH 0653/1866] tests compress with truth-y value --- catchtest/test_compress.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/catchtest/test_compress.cpp b/catchtest/test_compress.cpp index 6050ca05..f2003852 100644 --- a/catchtest/test_compress.cpp +++ b/catchtest/test_compress.cpp @@ -73,3 +73,23 @@ TEST_CASE("compress: binds to lvalues, moves rvalues", "[compress]") { REQUIRE( bi.was_moved_from() ); } } + +struct BoolLike { + public: + bool state; + explicit operator bool() const { + return this->state; + } +}; + +TEST_CASE("compress: workds with truthy and falsey values", "[compress]") { + std::vector bvec{{true}, {false}, {true}, {false}}; + + Vec ivec{1,2,3,4}; + + auto c = compress(ivec, bvec); + Vec v(std::begin(c), std::end(c)); + + Vec vc = {1,3}; + REQUIRE( v == vc ); +} From 9d8b2f8781edb104bb436fdb11fc58321630c46f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 11 Dec 2014 22:11:45 -0500 Subject: [PATCH 0654/1866] tests compress withs shorter selector list --- catchtest/test_compress.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/catchtest/test_compress.cpp b/catchtest/test_compress.cpp index f2003852..1bcb6c59 100644 --- a/catchtest/test_compress.cpp +++ b/catchtest/test_compress.cpp @@ -93,3 +93,10 @@ TEST_CASE("compress: workds with truthy and falsey values", "[compress]") { Vec vc = {1,3}; REQUIRE( v == vc ); } + +TEST_CASE("compress: terminates on shorter selectors", "[compress]") { + std::vector ivec{1, 2, 3, 4, 5}; + std::vector bvec{true}; + auto c = compress(ivec, bvec); + REQUIRE( std::distance(std::begin(c), std::end(c)) == 1 ); +} From 4abcb93dd21a71f0372448e1cb74f20a88460602 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 11 Dec 2014 22:13:49 -0500 Subject: [PATCH 0655/1866] tests compress with shorter data list --- catchtest/test_compress.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/catchtest/test_compress.cpp b/catchtest/test_compress.cpp index 1bcb6c59..1311997a 100644 --- a/catchtest/test_compress.cpp +++ b/catchtest/test_compress.cpp @@ -100,3 +100,10 @@ TEST_CASE("compress: terminates on shorter selectors", "[compress]") { auto c = compress(ivec, bvec); REQUIRE( std::distance(std::begin(c), std::end(c)) == 1 ); } + +TEST_CASE("compress: terminates on shorter data", "[compress]") { + std::vector ivec{1}; + std::vector bvec{true, true, true, true, true}; + auto c = compress(ivec, bvec); + REQUIRE( std::distance(std::begin(c), std::end(c)) == 1 ); +} From 923b97d4158b689d78ee67009e5cc98cec690caa Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 10:02:49 -0500 Subject: [PATCH 0656/1866] tests compress with empty selectors --- catchtest/test_compress.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/catchtest/test_compress.cpp b/catchtest/test_compress.cpp index 1311997a..e46f3e93 100644 --- a/catchtest/test_compress.cpp +++ b/catchtest/test_compress.cpp @@ -107,3 +107,10 @@ TEST_CASE("compress: terminates on shorter data", "[compress]") { auto c = compress(ivec, bvec); REQUIRE( std::distance(std::begin(c), std::end(c)) == 1 ); } + +TEST_CASE("compress: nothing on empty selectors", "[compress]") { + std::vector ivec{1,2,3}; + std::vector bvec{}; + auto c = compress(ivec, bvec); + REQUIRE( std::begin(c) == std::end(c) ); +} From 2f49ae1164fc989e193e3ed690a3b952cc7e0755 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 10:06:04 -0500 Subject: [PATCH 0657/1866] tests compress with empty data --- catchtest/test_compress.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/catchtest/test_compress.cpp b/catchtest/test_compress.cpp index e46f3e93..4a970814 100644 --- a/catchtest/test_compress.cpp +++ b/catchtest/test_compress.cpp @@ -114,3 +114,10 @@ TEST_CASE("compress: nothing on empty selectors", "[compress]") { auto c = compress(ivec, bvec); REQUIRE( std::begin(c) == std::end(c) ); } + +TEST_CASE("compress: nothing on empty data", "[compress]") { + std::vector ivec{}; + std::vector bvec{true, true, true}; + auto c = compress(ivec, bvec); + REQUIRE( std::begin(c) == std::end(c) ); +} From c9aa31c90b9aa68351cfd5f8879881181996dc38 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 10:33:13 -0500 Subject: [PATCH 0658/1866] fixes count includes --- count.hpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/count.hpp b/count.hpp index 4945d88f..491d7b2d 100644 --- a/count.hpp +++ b/count.hpp @@ -1,5 +1,5 @@ -#ifndef COUNT__H__ -#define COUNT__H__ +#ifndef ITER_COUNT_H_ +#define ITER_COUNT_H_ #include "range.hpp" @@ -29,5 +29,4 @@ namespace iter { } -#endif //define COUNT__H__ - +#endif From e96fe1f90debec5cce1c949cb291571205bfdbc4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 10:34:37 -0500 Subject: [PATCH 0659/1866] removes unnecessary include of --- catchtest/test_compress.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/catchtest/test_compress.cpp b/catchtest/test_compress.cpp index 4a970814..137f69c9 100644 --- a/catchtest/test_compress.cpp +++ b/catchtest/test_compress.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include #include From 97e8e3ae98fda2dcb77ccd65a3b9969e907427dc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 10:44:22 -0500 Subject: [PATCH 0660/1866] adds basic count test --- catchtest/test_count.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 catchtest/test_count.cpp diff --git a/catchtest/test_count.cpp b/catchtest/test_count.cpp new file mode 100644 index 00000000..ae7f35b0 --- /dev/null +++ b/catchtest/test_count.cpp @@ -0,0 +1,21 @@ +#include "helpers.hpp" +#include + +#include +#include +#include + +#include "catch.hpp" + +using iter::count; + +TEST_CASE("count: watch for 10 elements", "[count]") { + std::vector v{}; + for (auto i : count()) { + v.push_back(i); + if (i == 9) break; + } + + const std::vector vc{0,1,2,3,4,5,6,7,8,9}; + REQUIRE( v == vc ); +} From a4075c6eab831a944832a13c8418092ac6a1c238 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 10:46:41 -0500 Subject: [PATCH 0661/1866] adds count with starting value test --- catchtest/test_count.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/catchtest/test_count.cpp b/catchtest/test_count.cpp index ae7f35b0..9c7b23b7 100644 --- a/catchtest/test_count.cpp +++ b/catchtest/test_count.cpp @@ -19,3 +19,14 @@ TEST_CASE("count: watch for 10 elements", "[count]") { const std::vector vc{0,1,2,3,4,5,6,7,8,9}; REQUIRE( v == vc ); } + +TEST_CASE("count: start at 10", "[count]") { + std::vector v{}; + for (auto i : count(10)) { + v.push_back(i); + if (i == 14) break; + } + + const std::vector vc{10,11,12,13,14,15}; + REQUIRE( v == vc ); +} From 9f60d8c6831eff9cc32ffa9b1912897c30d4bc9c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 10:50:52 -0500 Subject: [PATCH 0662/1866] fixes count recursive call with start --- count.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/count.hpp b/count.hpp index 491d7b2d..579edceb 100644 --- a/count.hpp +++ b/count.hpp @@ -24,7 +24,7 @@ namespace iter { template Range count(T start) { - return range(start, T(1)); + return count(start, T(1)); } } From e9e8845e83150b17916dc14b7b10e6f8f11e2a8d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 11:03:16 -0500 Subject: [PATCH 0663/1866] tests count with negative step --- catchtest/test_count.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/catchtest/test_count.cpp b/catchtest/test_count.cpp index 9c7b23b7..0e5b660e 100644 --- a/catchtest/test_count.cpp +++ b/catchtest/test_count.cpp @@ -27,6 +27,17 @@ TEST_CASE("count: start at 10", "[count]") { if (i == 14) break; } - const std::vector vc{10,11,12,13,14,15}; + const std::vector vc{10,11,12,13,14}; REQUIRE( v == vc ); } + +TEST_CASE("count with step", "[count]") { + std::vector v{}; + for (auto i : count(2, -1)) { + v.push_back(i); + if (i == -3) break; + } + + const std::vector vc{2,1,0,-1,-2,-3}; + REQUIRE( v == vc); +} From 7eee264f14a1b648792e1b368de52a9224049434 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 12:02:23 -0500 Subject: [PATCH 0664/1866] adds count test with step >1 --- catchtest/test_count.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/catchtest/test_count.cpp b/catchtest/test_count.cpp index 0e5b660e..05134724 100644 --- a/catchtest/test_count.cpp +++ b/catchtest/test_count.cpp @@ -31,7 +31,7 @@ TEST_CASE("count: start at 10", "[count]") { REQUIRE( v == vc ); } -TEST_CASE("count with step", "[count]") { +TEST_CASE("count: with step", "[count]") { std::vector v{}; for (auto i : count(2, -1)) { v.push_back(i); @@ -41,3 +41,14 @@ TEST_CASE("count with step", "[count]") { const std::vector vc{2,1,0,-1,-2,-3}; REQUIRE( v == vc); } + +TEST_CASE("count: with step > 1", "[count]") { + std::vector v{}; + for (auto i : count(10, 2)) { + v.push_back(i); + if (i == 16) break; + } + + const std::vector vc{10, 12, 14, 16}; + REQUIRE( v == vc ); +} From 1ef8cc7f65157722fe719942b79a50cbdd1308dc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 12:56:16 -0500 Subject: [PATCH 0665/1866] builds count test --- catchtest/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index 4e5637e7..355e0139 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -23,6 +23,7 @@ progs = Split( combinations combinations_with_replacement compress + count ''' ) From 812aaa37db3ffae36c5677711c19e7728ac8241d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 13:03:54 -0500 Subject: [PATCH 0666/1866] adds basic cycle test --- catchtest/test_cycle.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 catchtest/test_cycle.cpp diff --git a/catchtest/test_cycle.cpp b/catchtest/test_cycle.cpp new file mode 100644 index 00000000..35dcc10a --- /dev/null +++ b/catchtest/test_cycle.cpp @@ -0,0 +1,26 @@ +#include + +#include "helpers.hpp" + +#include +#include +#include + +#include "catch.hpp" + +using iter::cycle; + +TEST_CASE("cycle: iterate twice", "[cycle]") { + std::vector ns {2,4,6}; + std::vector v{}; + std::size_t count = 0; + for (auto i : cycle(ns)) { + v.push_back(i); + ++count; + if (count == ns.size() * 2) break; + } + + auto vc = ns; + vc.insert(std::end(vc), std::begin(ns), std::end(ns)); + REQUIRE( v == vc ); +} From 79753f66ba795ad53c8cb0f82b477ebf4c7c6ef4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 13:04:41 -0500 Subject: [PATCH 0667/1866] fixes include guards in cycle --- cycle.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cycle.hpp b/cycle.hpp index d683b8da..421876f8 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -1,5 +1,5 @@ -#ifndef CYCLE__H__ -#define CYCLE__H__ +#ifndef ITER_CYCLE_H_ +#define ITER_CYCLE_H_ #include "iterbase.hpp" @@ -100,4 +100,4 @@ namespace iter { } } -#endif //ifndef CYCLE__H__ +#endif From a5fa8272d47652515e202be6f059b2c5d35f2251 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 13:10:31 -0500 Subject: [PATCH 0668/1866] cycle iter inherits from std::iterator --- cycle.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cycle.hpp b/cycle.hpp index 421876f8..ac8ab827 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -34,12 +34,12 @@ namespace iter { Cycle(Container container) : container(std::forward(container)) { } - Cycle() = delete; - Cycle& operator=(const Cycle&) = delete; public: - Cycle(const Cycle&) = default; - class Iterator { + class Iterator + : public std::iterator> + { private: using iter_type = iterator_type; iterator_type sub_iter; From 4e044ea43bf37a83f2144d2eb75358ac508dc8e8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 13:11:41 -0500 Subject: [PATCH 0669/1866] adds cycle iter == --- cycle.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cycle.hpp b/cycle.hpp index ac8ab827..7c801578 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -73,6 +73,10 @@ namespace iter { constexpr bool operator!=(const Iterator&) const { return true; } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } }; Iterator begin() { From 8e41b405c4d8346d2c5cd181fde422fa1eaf0a78 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 13:12:07 -0500 Subject: [PATCH 0670/1866] adds cycle iter postfix ++ --- cycle.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cycle.hpp b/cycle.hpp index 7c801578..b5e8ec64 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -70,6 +70,12 @@ namespace iter { return *this; } + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + constexpr bool operator!=(const Iterator&) const { return true; } From 42bcf378c4b16398dfa1416daf18c43bfd89496d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 13:12:45 -0500 Subject: [PATCH 0671/1866] makes cycle iter assignable --- cycle.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cycle.hpp b/cycle.hpp index b5e8ec64..8a3f7d9c 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -43,8 +43,8 @@ namespace iter { private: using iter_type = iterator_type; iterator_type sub_iter; - const iterator_type begin; - const iterator_type end; + iterator_type begin; + iterator_type end; public: Iterator (iterator_type iter, iterator_type end) From bcd44bbfea122e5b400a295b070223005f237702 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 13:14:14 -0500 Subject: [PATCH 0672/1866] cycle iterators actually compare It turns out there actually is a case where begin() and end() compare equal, and thats a cycle over an empty list. This is the same behavior as pythons cycle([]) which raises stop iteration right away --- cycle.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cycle.hpp b/cycle.hpp index 8a3f7d9c..adb2d58f 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -76,8 +76,8 @@ namespace iter { return ret; } - constexpr bool operator!=(const Iterator&) const { - return true; + bool operator!=(const Iterator& other) const { + return this->sub_iter != other.sub_iter; } bool operator==(const Iterator& other) const { From 3bedbd307f85cbcd12e65641e415b50a62f37a06 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 13:15:57 -0500 Subject: [PATCH 0673/1866] Removes placement new in favor of assignment I'm dont with that idea. It felt like dark magic to begin with --- cycle.hpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cycle.hpp b/cycle.hpp index adb2d58f..8c8962e1 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -61,11 +61,7 @@ namespace iter { ++this->sub_iter; // reset to beginning upon reaching the end if (!(this->sub_iter != this->end)) { - // explicit destruction with placement new in order - // to support iterators with no operator= - this->sub_iter.~iter_type(); - new(&this->sub_iter) iterator_type( - this->begin); + this->sub_iter = this->begin; } return *this; } From 5c81b9b9f328b93f3c535db31a1e5b8f99c69bd0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 13:18:39 -0500 Subject: [PATCH 0674/1866] makes sure cycle binds and moves correctly --- catchtest/test_cycle.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/catchtest/test_cycle.cpp b/catchtest/test_cycle.cpp index 35dcc10a..1c729877 100644 --- a/catchtest/test_cycle.cpp +++ b/catchtest/test_cycle.cpp @@ -24,3 +24,22 @@ TEST_CASE("cycle: iterate twice", "[cycle]") { vc.insert(std::end(vc), std::begin(ns), std::end(ns)); REQUIRE( v == vc ); } + +TEST_CASE("cycle: empty cycle terminates", "[cycle]") { + std::vector ns; + auto c = cycle(ns); + std::vector v(std::begin(c), std::end(c)); + REQUIRE( v.empty() ); +} + +TEST_CASE("cycle: binds to lvalues, moves rvalues", "[cycle]") { + itertest::BasicIterable bi{'x', 'y', 'z'}; + SECTION("binds to lvalues") { + cycle(bi); + REQUIRE_FALSE( bi.was_moved_from() ); + } + SECTION("moves rvalues") { + cycle(std::move(bi)); + REQUIRE( bi.was_moved_from() ); + } +} From 9fcf5a5b0a0f4c28d782bb33514875d5e3781354 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 13:27:45 -0500 Subject: [PATCH 0675/1866] makes sure cycle doesn't copy or move elements --- catchtest/test_cycle.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/catchtest/test_cycle.cpp b/catchtest/test_cycle.cpp index 1c729877..7f3d4203 100644 --- a/catchtest/test_cycle.cpp +++ b/catchtest/test_cycle.cpp @@ -43,3 +43,10 @@ TEST_CASE("cycle: binds to lvalues, moves rvalues", "[cycle]") { REQUIRE( bi.was_moved_from() ); } } + +TEST_CASE("cycle: doesn't move or copy elements of iterable", + "[cycle]") { + constexpr itertest::SolidInt arr[] = {{6}, {7}, {8}}; + auto c = cycle(arr); + *std::begin(c); +} From ccd67f2b768af47e27865ff2a31b299f1903ba10 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 13:28:19 -0500 Subject: [PATCH 0676/1866] builds cycle test --- catchtest/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index 355e0139..d9dc90da 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -24,6 +24,7 @@ progs = Split( combinations_with_replacement compress count + cycle ''' ) From 554ee53a42e51417f4c4eb10f359a59f1897ceb5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 13:52:04 -0500 Subject: [PATCH 0677/1866] ignores better --- tests/.gitignore | 33 ++------------------------------- 1 file changed, 2 insertions(+), 31 deletions(-) diff --git a/tests/.gitignore b/tests/.gitignore index 7daa7f9d..a77d502e 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,34 +1,5 @@ *.o *.swp -testaccumulate -testchain -testchainfromiterable -testcycle -testenumerate -testrange -testslice -testzip -testreversed -testrepeat -testfilter -testzip_longest -testdropwhile -testproduct -testpermutations -testcompress -testcombinations_with_replacement -testtakewhile -testcombinations -testpowerset -testsliding_window -testimap -testfilterfalse -testcount -testgrouper -testcommand_chains -testgroupby -testsorted -testunique_justseen -testunique_everseen +test* +!test*.cpp .sconsign.dblite - From 327cd45f3fd51d8dedea93c908e0a7df768bfc40 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 16:22:45 -0500 Subject: [PATCH 0678/1866] adds basic dropwhile test --- catchtest/test_dropwhile.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 catchtest/test_dropwhile.cpp diff --git a/catchtest/test_dropwhile.cpp b/catchtest/test_dropwhile.cpp new file mode 100644 index 00000000..93f99050 --- /dev/null +++ b/catchtest/test_dropwhile.cpp @@ -0,0 +1,21 @@ +#include + +#include "helpers.hpp" + +#include +#include +#include + +#include "catch.hpp" + +using iter::dropwhile; + +using Vec = const std::vector; + +TEST_CASE("dropwhile: skips initial elements", "[dropwhile]") { + Vec ns{1,2,3,4,5,6,7,8}; + auto d = dropwhile([](int i){return i < 5; }, ns); + Vec v(std::begin(d), std::end(d)); + Vec vc = {5,6,7,8}; + REQUIRE( v == vc ); +} From a6c8fa3757d378495965c98fef19efa8bcc81fec Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 16:22:57 -0500 Subject: [PATCH 0679/1866] dropwhile iter inherits from std::iterator --- dropwhile.hpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index fe727916..b24d14f6 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -1,5 +1,5 @@ -#ifndef DROPWHILE__H__ -#define DROPWHILE__H__ +#ifndef ITER_DROPWHILE_H_ +#define ITER_DROPWHILE_H_ #include @@ -43,7 +43,10 @@ namespace iter { public: DropWhile(const DropWhile&) = default; - class Iterator { + class Iterator + : public std::iterator> + { private: iterator_type sub_iter; const iterator_type sub_end; @@ -111,4 +114,4 @@ namespace iter { } } -#endif //ifndef DROPWHILE__H__ +#endif From 52f91cb7488bae116b6239faefe78db26a1df507 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 16:23:05 -0500 Subject: [PATCH 0680/1866] builds dropwhile catch test --- catchtest/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index d9dc90da..5bc85a89 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -25,6 +25,7 @@ progs = Split( compress count cycle + dropwhile ''' ) From 041daef2b41d11ecc1f27f8c9adedf14e02bc079 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 16:28:44 -0500 Subject: [PATCH 0681/1866] adds == and postfix ++ to dropwhile iter --- dropwhile.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dropwhile.hpp b/dropwhile.hpp index b24d14f6..28e823eb 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -80,9 +80,19 @@ namespace 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() { From c2cd81566ca5ad69a2ef36cd1e861565f58768af Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 17:07:16 -0500 Subject: [PATCH 0682/1866] tests dropwhile when all elements pass predicate --- catchtest/test_dropwhile.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/catchtest/test_dropwhile.cpp b/catchtest/test_dropwhile.cpp index 93f99050..e2c7e6d8 100644 --- a/catchtest/test_dropwhile.cpp +++ b/catchtest/test_dropwhile.cpp @@ -19,3 +19,11 @@ TEST_CASE("dropwhile: skips initial elements", "[dropwhile]") { Vec vc = {5,6,7,8}; REQUIRE( v == vc ); } + +TEST_CASE("dropwhile: doesn't skip anything if it shouldn't", "[dropwhile]") { + Vec ns {3,4,5,6}; + auto d = dropwhile([](int i){return i < 3; }, ns); + Vec v(std::begin(d), std::end(d)); + Vec vc = {3,4,5,6}; + REQUIRE( v == vc ); +} From ff3eba52c90f7ac9d472c4426a685d02caab2086 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 17:09:07 -0500 Subject: [PATCH 0683/1866] dropwhile skips everything test --- catchtest/test_dropwhile.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/catchtest/test_dropwhile.cpp b/catchtest/test_dropwhile.cpp index e2c7e6d8..c0453a2c 100644 --- a/catchtest/test_dropwhile.cpp +++ b/catchtest/test_dropwhile.cpp @@ -27,3 +27,11 @@ TEST_CASE("dropwhile: doesn't skip anything if it shouldn't", "[dropwhile]") { Vec vc = {3,4,5,6}; REQUIRE( v == vc ); } + +TEST_CASE("dropwhile: skips all elements when all are true under predicate", + "[dropwhile]") { + Vec ns {3,4,5,6}; + auto d = dropwhile([](int i){return i != 0; }, ns); + REQUIRE( std::begin(d) == std::end(d) ); +} + From 7ea60f7aad934a7abb6aa72fe23dd15b8cf19f48 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 17:10:41 -0500 Subject: [PATCH 0684/1866] adds dropwhile empty test --- catchtest/test_dropwhile.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/catchtest/test_dropwhile.cpp b/catchtest/test_dropwhile.cpp index c0453a2c..61542230 100644 --- a/catchtest/test_dropwhile.cpp +++ b/catchtest/test_dropwhile.cpp @@ -35,3 +35,8 @@ TEST_CASE("dropwhile: skips all elements when all are true under predicate", REQUIRE( std::begin(d) == std::end(d) ); } +TEST_CASE("dropwhile: empty case is empty", "[dropwhile]") { + Vec ns{}; + auto d = dropwhile([](int i){return i != 0; }, ns); + REQUIRE( std::begin(d) == std::end(d) ); +} From ac591509b85080f1b0825bb2bb5ff1a48a8b8cca Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 17:11:40 -0500 Subject: [PATCH 0685/1866] tests that dropwhile only drops from front --- catchtest/test_dropwhile.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/catchtest/test_dropwhile.cpp b/catchtest/test_dropwhile.cpp index 61542230..e9f3cc06 100644 --- a/catchtest/test_dropwhile.cpp +++ b/catchtest/test_dropwhile.cpp @@ -40,3 +40,11 @@ TEST_CASE("dropwhile: empty case is empty", "[dropwhile]") { auto d = dropwhile([](int i){return i != 0; }, ns); REQUIRE( std::begin(d) == std::end(d) ); } + +TEST_CASE("dropwhile: only drops from beginning", "[dropwhile]") { + Vec ns {1,2,3,4,5,6,5,4,3,2,1}; + auto d = dropwhile([](int i){return i < 5; }, ns); + Vec v(std::begin(d), std::end(d)); + Vec vc = {5,6,5,4,3,2,1}; + REQUIRE( v == vc ); +} From 8982da1f234161064e0296d61a37d503226adacc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 17:37:29 -0500 Subject: [PATCH 0686/1866] tests that dropwhile binds and moves correctly --- catchtest/test_dropwhile.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/catchtest/test_dropwhile.cpp b/catchtest/test_dropwhile.cpp index e9f3cc06..3fe6e7ab 100644 --- a/catchtest/test_dropwhile.cpp +++ b/catchtest/test_dropwhile.cpp @@ -48,3 +48,29 @@ TEST_CASE("dropwhile: only drops from beginning", "[dropwhile]") { Vec vc = {5,6,5,4,3,2,1}; REQUIRE( v == vc ); } + +namespace { + int less_than_five(int i) { + return i < 5; + } +} + +TEST_CASE("dropwhile: works with function pointer", "[dropwhile]") { + Vec ns{1,2,3,4,5,6,7,8}; + auto d = dropwhile(less_than_five, ns); + Vec v(std::begin(d), std::end(d)); + Vec vc = {5,6,7,8}; + REQUIRE( v == vc ); +} + +TEST_CASE("dropwhile: binds to lvalues, moves rvalues", "[dropwhile]") { + itertest::BasicIterable bi{1,2,3,4}; + SECTION("binds to lvalues") { + dropwhile(less_than_five, bi); + REQUIRE_FALSE( bi.was_moved_from() ); + } + SECTION("moves rvalues") { + dropwhile(less_than_five, std::move(bi)); + REQUIRE( bi.was_moved_from() ); + } +} From aaa7cd52fec77b230ffb2eac58086f23eedf8a67 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 12 Dec 2014 17:40:42 -0500 Subject: [PATCH 0687/1866] tests dropwhile with solidint --- catchtest/test_dropwhile.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/catchtest/test_dropwhile.cpp b/catchtest/test_dropwhile.cpp index 3fe6e7ab..07b6b907 100644 --- a/catchtest/test_dropwhile.cpp +++ b/catchtest/test_dropwhile.cpp @@ -74,3 +74,12 @@ TEST_CASE("dropwhile: binds to lvalues, moves rvalues", "[dropwhile]") { REQUIRE( bi.was_moved_from() ); } } + +TEST_CASE("dropwhile: doesn't move or copy elements of iterable", + "[dropwhile]") { + constexpr itertest::SolidInt arr[] = {{6}, {7}, {8}}; + for (auto&& i : dropwhile( + [](const itertest::SolidInt&){return false;} , arr)) { + (void)i; + } +} From e219b44fd3f5807a137e7278acb2a5ba495498f7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 13 Dec 2014 14:11:57 -0500 Subject: [PATCH 0688/1866] adds filter catch tests --- catchtest/test_filter.cpp | 54 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 catchtest/test_filter.cpp diff --git a/catchtest/test_filter.cpp b/catchtest/test_filter.cpp new file mode 100644 index 00000000..23313b61 --- /dev/null +++ b/catchtest/test_filter.cpp @@ -0,0 +1,54 @@ +#include + +#include "helpers.hpp" + +#include +#include +#include + +#include "catch.hpp" + +using iter::filter; + +using Vec = const std::vector; + +namespace { + bool less_than_five(int i) { + return i < 5; + } + + class LessThanValue { + private: + int compare_val; + + public: + LessThanValue(int v) : compare_val(v) { } + + bool operator() (int i) { + return i < this->compare_val; + } + }; +} + +TEST_CASE("filter: handles different functor types", "[filter]") { + Vec ns = {1,2, 5,6, 3,1, 7, -1, 5}; + Vec vc = {1,2,3,1,-1}; + SECTION("with function pointer") { + auto f = filter(less_than_five, ns); + Vec v(std::begin(f), std::end(f)); + REQUIRE( v == vc ); + } + + SECTION("with callable object") { + auto f = filter(LessThanValue{5}, ns); + Vec v(std::begin(f), std::end(f)); + REQUIRE( v == vc ); + } + + SECTION("with lambda") { + auto ltf = [](int i) {return i < 5;}; + auto f = filter(ltf, ns); + Vec v(std::begin(f), std::end(f)); + REQUIRE( v == vc ); + } +} From b051431b843082800c2effacb043053589983918 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 13 Dec 2014 14:12:21 -0500 Subject: [PATCH 0689/1866] filter iter inherits from std iterator --- filter.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/filter.hpp b/filter.hpp index 50871be9..a5459540 100644 --- a/filter.hpp +++ b/filter.hpp @@ -45,7 +45,10 @@ namespace iter { public: Filter(const Filter&) = default; - class Iterator { + class Iterator + : public std::iterator> + { protected: iterator_type sub_iter; const iterator_type sub_end; From 1a95d8d03ff56e9fdf10c41aef769f1f7fe598c1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 13 Dec 2014 14:12:55 -0500 Subject: [PATCH 0690/1866] adds filter iter postfix ++ --- filter.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/filter.hpp b/filter.hpp index a5459540..ebd47a32 100644 --- a/filter.hpp +++ b/filter.hpp @@ -84,6 +84,12 @@ namespace 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; } From bc4b1235bfe833c1fa3b7ad8e69d30d6a31e337a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 13 Dec 2014 14:14:17 -0500 Subject: [PATCH 0691/1866] adds filter iter == --- filter.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/filter.hpp b/filter.hpp index ebd47a32..b2a26bb5 100644 --- a/filter.hpp +++ b/filter.hpp @@ -93,6 +93,10 @@ namespace iter { bool operator!=(const Iterator& other) const { return this->sub_iter != other.sub_iter; } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } }; Iterator begin() { From 35eaa25c1ed5101a42da10f6c24b005a00e6f83e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 13 Dec 2014 14:14:34 -0500 Subject: [PATCH 0692/1866] makes filter iterators assignable --- filter.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/filter.hpp b/filter.hpp index b2a26bb5..7d5e8f4e 100644 --- a/filter.hpp +++ b/filter.hpp @@ -51,7 +51,7 @@ namespace iter { { protected: iterator_type sub_iter; - const iterator_type sub_end; + iterator_type sub_end; FilterFunc filter_func; // increment until the iterator points to is true on the From b712013f7f80bfae735daec932f479dd5999ac6a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 13 Dec 2014 14:18:25 -0500 Subject: [PATCH 0693/1866] tests 1 argument version of filter --- catchtest/test_filter.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/catchtest/test_filter.cpp b/catchtest/test_filter.cpp index 23313b61..24f7d19d 100644 --- a/catchtest/test_filter.cpp +++ b/catchtest/test_filter.cpp @@ -52,3 +52,11 @@ TEST_CASE("filter: handles different functor types", "[filter]") { REQUIRE( v == vc ); } } + +TEST_CASE("filter: using identity", "[filter]") { + Vec ns{0, 1, 2, 0, 3, 0, 0, 0, 4, 5, 0}; + Vec vc = {1,2,3,4,5}; + auto f = filter(ns); + Vec v(std::begin(f), std::end(f)); + REQUIRE( v == vc ); +} From 82a8ce834bf1c9b0381e2f2f8332546b27c2543d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 13 Dec 2014 14:18:34 -0500 Subject: [PATCH 0694/1866] builds filter test --- catchtest/SConstruct | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index 5bc85a89..7125b925 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -15,7 +15,6 @@ env['ENV']['TERM'] = os.environ['TERM'] progs = Split( ''' - enumerate zip range accumulate @@ -26,6 +25,8 @@ progs = Split( count cycle dropwhile + enumerate + filter ''' ) From 3f93775c947a59aa1f0c283a053e433976d8a703 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 13 Dec 2014 14:18:55 -0500 Subject: [PATCH 0695/1866] removes trailing filter comment --- filter.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/filter.hpp b/filter.hpp index 7d5e8f4e..25a6950a 100644 --- a/filter.hpp +++ b/filter.hpp @@ -167,4 +167,4 @@ namespace iter { } -#endif // #ifndef ITER_FILTER_H_ +#endif From e46591e9ba2af417106b7e0f8ead91fe57ab22f5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 13 Dec 2014 14:25:34 -0500 Subject: [PATCH 0696/1866] makes Filter copyable and movable (when it can) Actually let's the compiler figure it out --- filter.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/filter.hpp b/filter.hpp index 25a6950a..28ab60b7 100644 --- a/filter.hpp +++ b/filter.hpp @@ -39,11 +39,8 @@ namespace iter { : container(std::forward(container)), filter_func(filter_func) { } - Filter() = delete; - Filter& operator=(const Filter&) = delete; public: - Filter(const Filter&) = default; class Iterator : public std::iterator Date: Sat, 13 Dec 2014 14:28:08 -0500 Subject: [PATCH 0697/1866] tests than filter moves and binds correctly --- catchtest/test_filter.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/catchtest/test_filter.cpp b/catchtest/test_filter.cpp index 24f7d19d..3975960f 100644 --- a/catchtest/test_filter.cpp +++ b/catchtest/test_filter.cpp @@ -60,3 +60,27 @@ TEST_CASE("filter: using identity", "[filter]") { Vec v(std::begin(f), std::end(f)); REQUIRE( v == vc ); } + +TEST_CASE("filter: binds to lvalues, moves rvales", "[filter]") { + itertest::BasicIterable bi{1,2,3,4}; + + SECTION("one-arg binds to lvalues") { + filter(bi); + REQUIRE_FALSE(bi.was_moved_from()); + } + + SECTION("two-arg binds to lvalues") { + filter(less_than_five, bi); + REQUIRE_FALSE(bi.was_moved_from()); + } + + SECTION("one-arg moves rvalues") { + filter(std::move(bi)); + REQUIRE(bi.was_moved_from()); + } + + SECTION("two-arg moves rvalues") { + filter(less_than_five, std::move(bi)); + REQUIRE(bi.was_moved_from()); + } +} From 6ed205d57bda1121ca5516c9343f66bacddff902 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 13 Dec 2014 14:29:07 -0500 Subject: [PATCH 0698/1866] ignores .swp files --- catchtest/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/catchtest/.gitignore b/catchtest/.gitignore index 427dd64a..c686c757 100644 --- a/catchtest/.gitignore +++ b/catchtest/.gitignore @@ -1,4 +1,5 @@ *.o +*.swp test_* !test_*.cpp .sconsign.dblite From 53db4ac2b60ed7a963eb74fa73c2bd464535f1cf Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 13 Dec 2014 14:33:41 -0500 Subject: [PATCH 0699/1866] tests filter with solidint --- catchtest/test_filter.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/catchtest/test_filter.cpp b/catchtest/test_filter.cpp index 3975960f..31fe2fba 100644 --- a/catchtest/test_filter.cpp +++ b/catchtest/test_filter.cpp @@ -84,3 +84,11 @@ TEST_CASE("filter: binds to lvalues, moves rvales", "[filter]") { REQUIRE(bi.was_moved_from()); } } + +TEST_CASE("filter: doesn't move or copy elements of iterable", "[filter]") { + constexpr itertest::SolidInt arr[] = {{1}, {0}, {2}}; + for (auto&& i : filter( + [](const itertest::SolidInt& si) {return si.getint();},arr)) { + (void)i; + } +} From b345a8a66a721886d660384cd336c780b8665e94 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 13 Dec 2014 19:07:24 -0500 Subject: [PATCH 0700/1866] uniform initialization in enumerate * --- enumerate.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enumerate.hpp b/enumerate.hpp index a3208cda..845b0412 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -77,7 +77,7 @@ namespace iter { { } IterYield operator*() { - return IterYield(this->index, *this->sub_iter); + return {this->index, *this->sub_iter}; } Iterator& operator++() { From 16962081276d47a098ee33aa14358b95b00b2283 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 13 Dec 2014 19:11:04 -0500 Subject: [PATCH 0701/1866] tests filter when all elements fail --- catchtest/test_filter.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/catchtest/test_filter.cpp b/catchtest/test_filter.cpp index 31fe2fba..eb21b2c2 100644 --- a/catchtest/test_filter.cpp +++ b/catchtest/test_filter.cpp @@ -55,9 +55,10 @@ TEST_CASE("filter: handles different functor types", "[filter]") { TEST_CASE("filter: using identity", "[filter]") { Vec ns{0, 1, 2, 0, 3, 0, 0, 0, 4, 5, 0}; - Vec vc = {1,2,3,4,5}; auto f = filter(ns); Vec v(std::begin(f), std::end(f)); + + Vec vc = {1,2,3,4,5}; REQUIRE( v == vc ); } @@ -85,6 +86,14 @@ TEST_CASE("filter: binds to lvalues, moves rvales", "[filter]") { } } + +TEST_CASE("filter: all elements fail predicate", "[filter]") { + Vec ns{10,20,30,40,50}; + auto f = filter(less_than_five, ns); + + REQUIRE( std::begin(f) == std::end(f) ); +} + TEST_CASE("filter: doesn't move or copy elements of iterable", "[filter]") { constexpr itertest::SolidInt arr[] = {{1}, {0}, {2}}; for (auto&& i : filter( From f4705aa47d101223e1826f6e4a477a28c0f33e0e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 13 Dec 2014 19:38:13 -0500 Subject: [PATCH 0702/1866] tests filterfalse with different callables --- catchtest/test_filterfalse.cpp | 54 ++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 catchtest/test_filterfalse.cpp diff --git a/catchtest/test_filterfalse.cpp b/catchtest/test_filterfalse.cpp new file mode 100644 index 00000000..9ee1dc69 --- /dev/null +++ b/catchtest/test_filterfalse.cpp @@ -0,0 +1,54 @@ +#include + +#include "helpers.hpp" + +#include +#include +#include + +#include "catch.hpp" + +using iter::filterfalse; + +using Vec = const std::vector; + +namespace { + bool less_than_five(int i) { + return i < 5; + } + + class LessThanValue { + private: + int compare_val; + + public: + LessThanValue(int v) : compare_val(v) { } + + bool operator() (int i) { + return i < this->compare_val; + } + }; +} + +TEST_CASE("filterfalse: handles different functor types", "[filterfalse]") { + Vec ns = {1,2, 5,6, 3,1, 7, -1, 5}; + Vec vc = {5,6,7,5}; + SECTION("with function pointer") { + auto f = filterfalse(less_than_five, ns); + Vec v(std::begin(f), std::end(f)); + REQUIRE( v == vc ); + } + + SECTION("with callable object") { + auto f = filterfalse(LessThanValue{5}, ns); + Vec v(std::begin(f), std::end(f)); + REQUIRE( v == vc ); + } + + SECTION("with lambda") { + auto ltf = [](int i) {return i < 5;}; + auto f = filterfalse(ltf, ns); + Vec v(std::begin(f), std::end(f)); + REQUIRE( v == vc ); + } +} From cefc86658985387c47079c09d559a7ea152f2348 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 13 Dec 2014 19:38:27 -0500 Subject: [PATCH 0703/1866] Adds non-const operator() to filter false If the incoming callable doesn't have an operator() const; then I need the PredicateFlipper to have a non-const operator() as well --- filterfalse.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/filterfalse.hpp b/filterfalse.hpp index 27e8cf03..38ded919 100644 --- a/filterfalse.hpp +++ b/filterfalse.hpp @@ -29,6 +29,11 @@ namespace iter { bool operator() (const iterator_deref item) const { return !bool(filter_func(item)); } + + // with non-const incase FilterFunc::operator() is non-const + bool operator() (const iterator_deref item) { + return !bool(filter_func(item)); + } }; // Reverses the bool() conversion result of anything that supports a From d2b56065d1d47b8058f05c4bc11dc2cc1b6fcbb0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 13 Dec 2014 19:39:48 -0500 Subject: [PATCH 0704/1866] builds filterfalse catchtest --- catchtest/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index 7125b925..46606e89 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -27,6 +27,7 @@ progs = Split( dropwhile enumerate filter + filterfalse ''' ) From 677ddda4965ce39478d3c0660075d9cfd7fc3343 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 13 Dec 2014 19:41:12 -0500 Subject: [PATCH 0705/1866] Tests one-arg filter false --- catchtest/test_filterfalse.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/catchtest/test_filterfalse.cpp b/catchtest/test_filterfalse.cpp index 9ee1dc69..1bd505d9 100644 --- a/catchtest/test_filterfalse.cpp +++ b/catchtest/test_filterfalse.cpp @@ -52,3 +52,12 @@ TEST_CASE("filterfalse: handles different functor types", "[filterfalse]") { REQUIRE( v == vc ); } } + +TEST_CASE("filterfalse: using identity", "[filterfalse]") { + Vec ns{0, 1, 2, 0, 3, 0, 0, 0, 4, 5, 0}; + auto f = filterfalse(ns); + Vec v(std::begin(f), std::end(f)); + + Vec vc = {0, 0, 0, 0, 0, 0}; + REQUIRE( v == vc ); +} From 5df09b9052257f297209f232422fad9a0abf19d2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 13 Dec 2014 19:45:17 -0500 Subject: [PATCH 0706/1866] makes sure filterfalse moves and binds correctly --- catchtest/test_filterfalse.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/catchtest/test_filterfalse.cpp b/catchtest/test_filterfalse.cpp index 1bd505d9..5ee8ea03 100644 --- a/catchtest/test_filterfalse.cpp +++ b/catchtest/test_filterfalse.cpp @@ -61,3 +61,27 @@ TEST_CASE("filterfalse: using identity", "[filterfalse]") { Vec vc = {0, 0, 0, 0, 0, 0}; REQUIRE( v == vc ); } + +TEST_CASE("filterfalse: binds to lvalues, moves rvales", "[filterfalse]") { + itertest::BasicIterable bi{1,2,3,4}; + + SECTION("one-arg binds to lvalues") { + filterfalse(bi); + REQUIRE_FALSE(bi.was_moved_from()); + } + + SECTION("two-arg binds to lvalues") { + filterfalse(less_than_five, bi); + REQUIRE_FALSE(bi.was_moved_from()); + } + + SECTION("one-arg moves rvalues") { + filterfalse(std::move(bi)); + REQUIRE(bi.was_moved_from()); + } + + SECTION("two-arg moves rvalues") { + filterfalse(less_than_five, std::move(bi)); + REQUIRE(bi.was_moved_from()); + } +} From e911bec91e8d6e8231ed709b6fdda81e2d9d8f51 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 13 Dec 2014 19:49:46 -0500 Subject: [PATCH 0707/1866] tests filterfalse when all elements fail predicate --- catchtest/test_filterfalse.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/catchtest/test_filterfalse.cpp b/catchtest/test_filterfalse.cpp index 5ee8ea03..ca6ec915 100644 --- a/catchtest/test_filterfalse.cpp +++ b/catchtest/test_filterfalse.cpp @@ -85,3 +85,10 @@ TEST_CASE("filterfalse: binds to lvalues, moves rvales", "[filterfalse]") { REQUIRE(bi.was_moved_from()); } } + +TEST_CASE("filterfalse: all elements pass predicate", "[filterfalse]") { + Vec ns{0,1,2,3,4}; + auto f = filterfalse(less_than_five, ns); + + REQUIRE( std::begin(f) == std::end(f) ); +} From 7565b8438805bee5078b184fec76c20df823600d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Dec 2014 18:28:33 -0500 Subject: [PATCH 0708/1866] adds basic groupby test --- catchtest/test_groupby.cpp | 43 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 catchtest/test_groupby.cpp diff --git a/catchtest/test_groupby.cpp b/catchtest/test_groupby.cpp new file mode 100644 index 00000000..83de6577 --- /dev/null +++ b/catchtest/test_groupby.cpp @@ -0,0 +1,43 @@ +#include + +#include "helpers.hpp" + +#include +#include +#include + +#include "catch.hpp" + +using iter::groupby; + +namespace { + int length(const std::string& s) { + return s.size(); + } +} + +TEST_CASE("groupby: groups words by length") { + const std::vector vec = { + "hi", "ab", "ho", + "abc", "def", + "abcde", "efghi" + }; + + std::vector keys; + std::vector> groups; + for (auto gb : groupby(vec, &length)) { + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + } + + const std::vector kc = {2, 3, 5}; + REQUIRE( keys == kc ); + + const std::vector> gc = { + {"hi", "ab", "ho"}, + {"abc", "def"}, + {"abcde", "efghi"}, + }; + + REQUIRE( groups == gc ); +} From 22663f097bcb93101be7ad0b761d35d9244ad754 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Dec 2014 18:28:46 -0500 Subject: [PATCH 0709/1866] GroupIterator inherits from std::iterator --- groupby.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/groupby.hpp b/groupby.hpp index e26a7e04..4febf64e 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -151,7 +151,10 @@ namespace iter { other.completed = true; } - class GroupIterator { + class GroupIterator + : public std::iterator> + { private: const key_func_ret key; const Group& group; From f0eddb4ade840a8fb98d7cfe58dca221da1ef873 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Dec 2014 18:29:21 -0500 Subject: [PATCH 0710/1866] builds groupby test --- catchtest/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index 46606e89..30ac43d8 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -28,6 +28,7 @@ progs = Split( enumerate filter filterfalse + groupby ''' ) From 81f22a889d429608c045913874790e418547dccc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Dec 2014 18:34:58 -0500 Subject: [PATCH 0711/1866] add GroupIterator == and postfix ++ --- groupby.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/groupby.hpp b/groupby.hpp index 4febf64e..a2c4639c 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -182,11 +182,21 @@ namespace iter { } } + bool operator==(const GroupIterator& other) const { + return !(*this != other); + } + GroupIterator& operator++() { this->group.owner.increment_iterator(); return *this; } + GroupIterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + iterator_deref operator*() { return this->group.owner.current(); } From 3e8de5bc81dd6f011d4ac2d1b205ad7c42f1d411 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Dec 2014 21:34:01 -0500 Subject: [PATCH 0712/1866] groupby iterator inherits from std iterator --- groupby.hpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index a2c4639c..fc3fc743 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -51,16 +51,20 @@ namespace iter { class Iterator; class Group; - class Iterator { + private: + using KeyGroupPair = + std::pair; + public: + + class Iterator + : public std::iterator + { private: iterator_type sub_iter; iterator_type sub_iter_peek; const iterator_type sub_end; KeyFunc key_func; - using KeyGroupPair = - std::pair; - public: Iterator (iterator_type si, iterator_type end, From c26959f5b1fe9437a9e27c79b0f09ae8321b935a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Dec 2014 21:35:55 -0500 Subject: [PATCH 0713/1866] adds groupby iterator == --- groupby.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/groupby.hpp b/groupby.hpp index fc3fc743..175b4728 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -90,6 +90,10 @@ namespace iter { return !this->exhausted(); } + bool operator==(const Iterator& other) const { + return !(*this != other); + } + void increment_iterator() { if (this->sub_iter != this->sub_end) { ++this->sub_iter; From 4cf5e9cf2a0c3ad234ba6a00ec60f411d58d6495 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Dec 2014 21:38:09 -0500 Subject: [PATCH 0714/1866] adds groupby iterator postfix++ I don't feel too good about this one, let it be known --- groupby.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/groupby.hpp b/groupby.hpp index 175b4728..79960c8b 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -86,6 +86,12 @@ namespace iter { return *this; } + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + bool operator!=(const Iterator&) const { return !this->exhausted(); } From d6a119c018321685d554576616a8e094c92daccf Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Dec 2014 22:29:59 -0500 Subject: [PATCH 0715/1866] tests that groups may be skipped --- catchtest/test_groupby.cpp | 52 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/catchtest/test_groupby.cpp b/catchtest/test_groupby.cpp index 83de6577..3540a950 100644 --- a/catchtest/test_groupby.cpp +++ b/catchtest/test_groupby.cpp @@ -14,15 +14,16 @@ namespace { int length(const std::string& s) { return s.size(); } -} -TEST_CASE("groupby: groups words by length") { const std::vector vec = { "hi", "ab", "ho", "abc", "def", "abcde", "efghi" }; +} + +TEST_CASE("groupby: groups words by length") { std::vector keys; std::vector> groups; for (auto gb : groupby(vec, &length)) { @@ -41,3 +42,50 @@ TEST_CASE("groupby: groups words by length") { REQUIRE( groups == gc ); } + +TEST_CASE("groupby: groups can be skipped completely", "[groupby]") { + std::vector keys; + std::vector> groups; + for (auto gb : groupby(vec, &length)) { + if (gb.first == 3) { + continue; + } + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + } + + const std::vector kc = {2, 5}; + REQUIRE( keys == kc ); + + const std::vector> gc = { + {"hi", "ab", "ho"}, + {"abcde", "efghi"}, + }; + + REQUIRE( groups == gc ); +} + +TEST_CASE("groupby: groups can be skipped partially", "[groupby]") { + std::vector keys; + std::vector> groups; + for (auto gb : groupby(vec, &length)) { + keys.push_back(gb.first); + if (gb.first == 3) { + std::vector cut_short = {*std::begin(gb.second)}; + groups.push_back(cut_short); + } else { + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + } + } + + const std::vector kc = {2, 3, 5}; + REQUIRE( keys == kc ); + + const std::vector> gc = { + {"hi", "ab", "ho"}, + {"abc"}, + {"abcde", "efghi"}, + }; + + REQUIRE( groups == gc ); +} From b0b1c92f82249b54ec960fb9ecd601625b915c97 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Dec 2014 22:38:10 -0500 Subject: [PATCH 0716/1866] tests single argument groupby --- catchtest/test_groupby.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/catchtest/test_groupby.cpp b/catchtest/test_groupby.cpp index 3540a950..f2fd484e 100644 --- a/catchtest/test_groupby.cpp +++ b/catchtest/test_groupby.cpp @@ -89,3 +89,27 @@ TEST_CASE("groupby: groups can be skipped partially", "[groupby]") { REQUIRE( groups == gc ); } + +TEST_CASE("groupby: single argument uses elements as keys", "[groupby]") { + std::vector ivec = {5, 5, 6, 6, 19, 19, 19, 19, 69, 0, 10, 10}; + std::vector keys; + std::vector> groups; + for (auto gb : groupby(ivec)) { + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + } + + const std::vector kc = {5, 6, 19, 69, 0, 10}; + REQUIRE( keys == kc ); + + std::vector> gc = { + {5, 5}, + {6, 6}, + {19, 19, 19, 19}, + {69}, + {0}, + {10, 10}, + }; + + REQUIRE( groups == gc ); +} From e1ca5b32f61b32abd40c64746d467675084cca73 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Dec 2014 22:45:33 -0500 Subject: [PATCH 0717/1866] tests groupby with empty iterable --- catchtest/test_groupby.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/catchtest/test_groupby.cpp b/catchtest/test_groupby.cpp index f2fd484e..d27da643 100644 --- a/catchtest/test_groupby.cpp +++ b/catchtest/test_groupby.cpp @@ -113,3 +113,9 @@ TEST_CASE("groupby: single argument uses elements as keys", "[groupby]") { REQUIRE( groups == gc ); } + +TEST_CASE("groupby: empty iterable yields nothing", "[groupby]") { + std::vector ivec{}; + auto g = groupby(ivec); + REQUIRE( std::begin(g) == std::end(g) ); +} From b111fcdc2861a916d7bff11a7203e1b18eb99e89 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 15 Dec 2014 00:55:04 -0500 Subject: [PATCH 0718/1866] tests groupby without iterating through groups --- catchtest/test_groupby.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/catchtest/test_groupby.cpp b/catchtest/test_groupby.cpp index d27da643..a1fbae32 100644 --- a/catchtest/test_groupby.cpp +++ b/catchtest/test_groupby.cpp @@ -26,7 +26,7 @@ namespace { TEST_CASE("groupby: groups words by length") { std::vector keys; std::vector> groups; - for (auto gb : groupby(vec, &length)) { + for (auto&& gb : groupby(vec, &length)) { keys.push_back(gb.first); groups.emplace_back(std::begin(gb.second), std::end(gb.second)); } @@ -46,7 +46,7 @@ TEST_CASE("groupby: groups words by length") { TEST_CASE("groupby: groups can be skipped completely", "[groupby]") { std::vector keys; std::vector> groups; - for (auto gb : groupby(vec, &length)) { + for (auto&& gb : groupby(vec, &length)) { if (gb.first == 3) { continue; } @@ -68,7 +68,7 @@ TEST_CASE("groupby: groups can be skipped completely", "[groupby]") { TEST_CASE("groupby: groups can be skipped partially", "[groupby]") { std::vector keys; std::vector> groups; - for (auto gb : groupby(vec, &length)) { + for (auto&& gb : groupby(vec, &length)) { keys.push_back(gb.first); if (gb.first == 3) { std::vector cut_short = {*std::begin(gb.second)}; @@ -94,7 +94,7 @@ TEST_CASE("groupby: single argument uses elements as keys", "[groupby]") { std::vector ivec = {5, 5, 6, 6, 19, 19, 19, 19, 69, 0, 10, 10}; std::vector keys; std::vector> groups; - for (auto gb : groupby(ivec)) { + for (auto&& gb : groupby(ivec)) { keys.push_back(gb.first); groups.emplace_back(std::begin(gb.second), std::end(gb.second)); } @@ -119,3 +119,13 @@ TEST_CASE("groupby: empty iterable yields nothing", "[groupby]") { auto g = groupby(ivec); REQUIRE( std::begin(g) == std::end(g) ); } + +TEST_CASE("groupby: inner iterator (group) not used", "[groupby]") { + std::vector keys; + for (auto&& gb : groupby(vec, length)) { + keys.push_back(gb.first); + } + + std::vector kc = {2, 3, 5}; + REQUIRE( keys == kc ); +} From 1cb217cf4ecd6813e5abcfcc5e154fabb14b131a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 8 Jan 2015 17:13:58 -0500 Subject: [PATCH 0719/1866] tests imap with different callables --- catchtest/test_imap.cpp | 50 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 catchtest/test_imap.cpp diff --git a/catchtest/test_imap.cpp b/catchtest/test_imap.cpp new file mode 100644 index 00000000..e104164a --- /dev/null +++ b/catchtest/test_imap.cpp @@ -0,0 +1,50 @@ +#include + +#include "helpers.hpp" + +#include +#include +#include + +#include "catch.hpp" + +using iter::imap; +using Vec = const std::vector; + +namespace { + int plusone(int i) { + return i + 1; + } + + class PlusOner { + public: + int operator()(int i) { + return i + 1; + } + }; +} + +TEST_CASE("imap: works with lambda, callable, and function", "[imap]") { + std::vector ns = {10, 20, 30}; + SECTION("with lambda") { + auto im = imap([](int i) { return i + 1; }, ns); + Vec v(std::begin(im), std::end(im)); + Vec vc = {11, 21, 31}; + REQUIRE(v == vc); + } + + SECTION("with function") { + auto im = imap(plusone, ns); + Vec v(std::begin(im), std::end(im)); + Vec vc = {11, 21, 31}; + REQUIRE(v == vc); + } + + SECTION("with function") { + auto im = imap(PlusOner{}, ns); + Vec v(std::begin(im), std::end(im)); + Vec vc = {11, 21, 31}; + REQUIRE(v == vc); + } + +} From 0cde291c19fe89c0971867fd9759d368214eeb8d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 8 Jan 2015 17:14:28 -0500 Subject: [PATCH 0720/1866] imap iter inherits from std::iterator --- imap.hpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/imap.hpp b/imap.hpp index fd6f0ecc..0f9bc485 100644 --- a/imap.hpp +++ b/imap.hpp @@ -78,6 +78,9 @@ namespace iter { private: MapFunc map_func; ZippedType zipped; + + using IMapIterDeref = decltype(detail::call_with_tuple( + map_func, *std::begin(zipped))); // Value constructor for use only in the imap function IMap(MapFunc map_func, Containers&& ... containers) : @@ -91,7 +94,9 @@ namespace iter { IMap(const IMap&) = default; IMap(IMap&&) = default; - class Iterator { + class Iterator + : public std::iterator + { private: MapFunc map_func; ZippedIterType zipiter; @@ -102,10 +107,7 @@ namespace iter { zipiter(zipiter) { } - auto operator*() -> - decltype(detail::call_with_tuple( - this->map_func, *(this->zipiter))) - { + IMapIterDeref operator*() { return detail::call_with_tuple( this->map_func, *(this->zipiter)); } From 2ae589345603ede5ff88f3c446431d95bc66898b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 8 Jan 2015 17:21:38 -0500 Subject: [PATCH 0721/1866] SConstruct builds imap test --- catchtest/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index 30ac43d8..8e4b799b 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -29,6 +29,7 @@ progs = Split( filter filterfalse groupby + imap ''' ) From a1ea801b42a283f816d5eeb4ce5634978ef1ba19 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 8 Jan 2015 17:28:55 -0500 Subject: [PATCH 0722/1866] tests imap with multiple sequences --- catchtest/test_imap.cpp | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/catchtest/test_imap.cpp b/catchtest/test_imap.cpp index e104164a..7532e93e 100644 --- a/catchtest/test_imap.cpp +++ b/catchtest/test_imap.cpp @@ -22,6 +22,14 @@ namespace { return i + 1; } }; + + int power(int b, int e) { + int acc = 1; + for (int i = 0; i < e; ++i) { + acc *= b; + } + return acc; + } } TEST_CASE("imap: works with lambda, callable, and function", "[imap]") { @@ -30,21 +38,32 @@ TEST_CASE("imap: works with lambda, callable, and function", "[imap]") { auto im = imap([](int i) { return i + 1; }, ns); Vec v(std::begin(im), std::end(im)); Vec vc = {11, 21, 31}; - REQUIRE(v == vc); + REQUIRE( v == vc ); } SECTION("with function") { auto im = imap(plusone, ns); Vec v(std::begin(im), std::end(im)); Vec vc = {11, 21, 31}; - REQUIRE(v == vc); + REQUIRE( v == vc ); } SECTION("with function") { auto im = imap(PlusOner{}, ns); Vec v(std::begin(im), std::end(im)); Vec vc = {11, 21, 31}; - REQUIRE(v == vc); + REQUIRE( v == vc ); } } + +TEST_CASE("imap: works with multiple sequences", "[imap]") { + Vec bases = {0, 1, 2, 3}; + Vec exps = {1, 2, 3, 4}; + + auto im = imap(power, bases, exps); + Vec v(std::begin(im), std::end(im)); + Vec vc = {0, 1, 8, 81}; + + REQUIRE( v == vc ); +} From 162889670fae9a39ae38b1e4dad9fe7699d85286 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 8 Jan 2015 17:35:08 -0500 Subject: [PATCH 0723/1866] tests imap with uneven sequences --- catchtest/test_imap.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/catchtest/test_imap.cpp b/catchtest/test_imap.cpp index 7532e93e..4749d1f2 100644 --- a/catchtest/test_imap.cpp +++ b/catchtest/test_imap.cpp @@ -67,3 +67,19 @@ TEST_CASE("imap: works with multiple sequences", "[imap]") { REQUIRE( v == vc ); } + +TEST_CASE("imap: terminates on shortest squence", "[imap]") { + Vec ns1 = {1, 2, 3, 4}; + Vec ns2 = {2, 4, 6, 8, 10}; + Vec vc = {3, 6, 9, 12}; + SECTION("shortest sequence first") { + auto im = imap([](int a, int b){ return a + b; }, ns1, ns2); + Vec v(std::begin(im), std::end(im)); + REQUIRE( v == vc ); + } + SECTION("shortest sequence second") { + auto im = imap([](int a, int b){ return a + b; }, ns2, ns1); + Vec v(std::begin(im), std::end(im)); + REQUIRE( v == vc ); + } +} From 7c0b37425c011d6ac882522ff4e04d6737b11b6e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 8 Jan 2015 20:15:25 -0500 Subject: [PATCH 0724/1866] imap correctness tests (copy/move/++) --- catchtest/test_imap.cpp | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/catchtest/test_imap.cpp b/catchtest/test_imap.cpp index 4749d1f2..71ae6c5a 100644 --- a/catchtest/test_imap.cpp +++ b/catchtest/test_imap.cpp @@ -33,7 +33,7 @@ namespace { } TEST_CASE("imap: works with lambda, callable, and function", "[imap]") { - std::vector ns = {10, 20, 30}; + Vec ns = {10, 20, 30}; SECTION("with lambda") { auto im = imap([](int i) { return i + 1; }, ns); Vec v(std::begin(im), std::end(im)); @@ -83,3 +83,34 @@ TEST_CASE("imap: terminates on shortest squence", "[imap]") { REQUIRE( v == vc ); } } + +TEST_CASE("imap: binds to lvalues, moves rvalues", "[imap]") { + itertest::BasicIterable bi{1, 2}; + SECTION("binds to lvalues") { + imap(plusone, bi); + REQUIRE_FALSE(bi.was_moved_from()); + } + + SECTION("moves rvalues") { + imap(plusone, std::move(bi)); + REQUIRE(bi.was_moved_from()); + } +} + +TEST_CASE("imap: doesn't move or copy elements of iterable", "[imap]") { + constexpr itertest::SolidInt arr[] = {{1}, {0}, {2}}; + for (auto&& i : imap([](const itertest::SolidInt& si){return si.getint();}, + arr)) { + (void)i; + } +} + +TEST_CASE("imap: postfix ++", "[imap]") { + Vec ns = {10, 20}; + auto im = imap(plusone, ns); + auto it = std::begin(im); + it++; + REQUIRE( (*it) == 21 ); + it++; + REQUIRE( it == std::end(im) ); +} From 86c833b9a8db2685a421b07abbda0a840727ee6e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 8 Jan 2015 20:16:04 -0500 Subject: [PATCH 0725/1866] adds imap iter == and postfix ++ --- imap.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/imap.hpp b/imap.hpp index 0f9bc485..ef0727fd 100644 --- a/imap.hpp +++ b/imap.hpp @@ -116,10 +116,20 @@ namespace iter { ++this->zipiter; return *this; } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } bool operator!=(const Iterator& other) const { return this->zipiter != other.zipiter; } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } }; Iterator begin() { From 5ab451d2f63d18620f10e46d8853b23c54ca8d0c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 8 Jan 2015 20:18:45 -0500 Subject: [PATCH 0726/1866] tests imap with empty sequence --- catchtest/test_imap.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/catchtest/test_imap.cpp b/catchtest/test_imap.cpp index 71ae6c5a..ba9ae171 100644 --- a/catchtest/test_imap.cpp +++ b/catchtest/test_imap.cpp @@ -84,6 +84,12 @@ TEST_CASE("imap: terminates on shortest squence", "[imap]") { } } +TEST_CASE("imap: empty sequence gives nothing", "[imap]") { + Vec v{}; + auto im = imap(plusone, v); + REQUIRE( std::begin(im) == std::end(im) ); +} + TEST_CASE("imap: binds to lvalues, moves rvalues", "[imap]") { itertest::BasicIterable bi{1, 2}; SECTION("binds to lvalues") { @@ -114,3 +120,4 @@ TEST_CASE("imap: postfix ++", "[imap]") { it++; REQUIRE( it == std::end(im) ); } + From 72b735c626703c4de6c89b0c4e3708501a7b3540 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 8 Jan 2015 20:21:22 -0500 Subject: [PATCH 0727/1866] fixes typo --- repeat.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/repeat.hpp b/repeat.hpp index 29991c9c..9753675d 100644 --- a/repeat.hpp +++ b/repeat.hpp @@ -6,7 +6,7 @@ namespace iter { - // must me negative + // must be negative constexpr int INFINITE_REPEAT = -1; template From 3daeff55e67e8404deccb028f25467c41a1b8884 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 8 Jan 2015 20:42:30 -0500 Subject: [PATCH 0728/1866] permutations iter inherits from std iterator --- permutations.hpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/permutations.hpp b/permutations.hpp index 08b24ef0..9785343a 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -6,7 +6,7 @@ #include #include #include - +#include namespace iter { @@ -15,15 +15,18 @@ namespace iter { private: Container container; + using Permutable = + std::vector>; + public: Permuter(Container in_container) : container(in_container) { } - class Iterator { + class Iterator + : public std::iterator + { private: - using Permutable = - std::vector>; Permutable working_set; bool is_not_last = true; From aefdddaa480e13171d4d3ff40e4859ce4ebea7f9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 8 Jan 2015 20:42:47 -0500 Subject: [PATCH 0729/1866] tests permutations basic functionality --- catchtest/test_permutations.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 catchtest/test_permutations.cpp diff --git a/catchtest/test_permutations.cpp b/catchtest/test_permutations.cpp new file mode 100644 index 00000000..35c5f9d8 --- /dev/null +++ b/catchtest/test_permutations.cpp @@ -0,0 +1,26 @@ +#include + +#include "helpers.hpp" + +#include +#include +#include + +#include "catch.hpp" + +using iter::permutations; +using IntPermSet = std::multiset>; + +TEST_CASE("permutations: basic test, 3 element sequence", "[permutations]") { + const std::vector ns = {1, 7, 9}; + auto p = permutations(ns); + + IntPermSet v; + for (auto&& st : p) { + v.emplace(std::begin(st), std::end(st)); + } + + const IntPermSet vc = + {{1, 7, 9}, {1, 9, 7}, {7, 1, 9}, {7, 9, 1}, {9, 1, 7}, {9, 7, 1}}; + REQUIRE( v == vc ); +} From eb74d12e6192ea27c236b551a8717570f52195db Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 8 Jan 2015 20:43:19 -0500 Subject: [PATCH 0730/1866] builds permutations test --- catchtest/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index 8e4b799b..daae60a4 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -30,6 +30,7 @@ progs = Split( filterfalse groupby imap + permutations ''' ) From 080e9da5e1a061e95d431839613b4d60af0d989a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 8 Jan 2015 20:50:35 -0500 Subject: [PATCH 0731/1866] tests permutations with empy sequence --- catchtest/test_permutations.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/catchtest/test_permutations.cpp b/catchtest/test_permutations.cpp index 35c5f9d8..8a55df64 100644 --- a/catchtest/test_permutations.cpp +++ b/catchtest/test_permutations.cpp @@ -24,3 +24,13 @@ TEST_CASE("permutations: basic test, 3 element sequence", "[permutations]") { {{1, 7, 9}, {1, 9, 7}, {7, 1, 9}, {7, 9, 1}, {9, 1, 7}, {9, 7, 1}}; REQUIRE( v == vc ); } + +TEST_CASE("permutations: empty sequence has one empy permutation", + "[permutations]") { + const std::vector ns{}; + auto p = permutations(ns); + auto it = std::begin(p); + REQUIRE( (*it).empty() ); + it++; + REQUIRE( it == std::end(p) ); +} From 9465324b65ae0f16d06e9f04a1d5d641047ae3b8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 8 Jan 2015 21:10:57 -0500 Subject: [PATCH 0732/1866] adds == and postfix ++ to permutations iter --- permutations.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/permutations.hpp b/permutations.hpp index 9785343a..d39b1433 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -54,9 +54,19 @@ namespace iter { return *this; } + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + bool operator!=(const Iterator&) const { return is_not_last; } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } }; Iterator begin() { From 420f670e03835573d7fe206036243f0a6eea3d38 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 8 Jan 2015 21:29:21 -0500 Subject: [PATCH 0733/1866] adds missing forward() in permutations ctor --- permutations.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/permutations.hpp b/permutations.hpp index d39b1433..bb383ac7 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -20,7 +20,7 @@ namespace iter { public: Permuter(Container in_container) - : container(in_container) + : container(std::forward(in_container)) { } class Iterator @@ -93,5 +93,4 @@ namespace iter { } -#endif // ITER_PERMUTATIONS_HPP_ - +#endif From ffd66f2e2ab14d2a00681698c8f9e83f25770e5d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 8 Jan 2015 21:29:45 -0500 Subject: [PATCH 0734/1866] tests that permutations binds and moves correctly --- catchtest/test_permutations.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/catchtest/test_permutations.cpp b/catchtest/test_permutations.cpp index 8a55df64..0c2cac0b 100644 --- a/catchtest/test_permutations.cpp +++ b/catchtest/test_permutations.cpp @@ -34,3 +34,16 @@ TEST_CASE("permutations: empty sequence has one empy permutation", it++; REQUIRE( it == std::end(p) ); } + +TEST_CASE("permutations: binds to lvalues, moves rvalues", "[permutations]") { + itertest::BasicIterable bi{1, 2}; + SECTION("binds to lvalues") { + permutations(bi); + REQUIRE_FALSE(bi.was_moved_from()); + } + + SECTION("moves rvalues") { + permutations(std::move(bi)); + REQUIRE(bi.was_moved_from()); + } +} From dc4a0a10a66d542b032653aa28e5b5182ab391c5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 8 Jan 2015 22:07:31 -0500 Subject: [PATCH 0735/1866] tests that permutations doesn't copy/move elems which is worth paying attention to since it has to make referenc_wrappers --- catchtest/test_permutations.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/catchtest/test_permutations.cpp b/catchtest/test_permutations.cpp index 0c2cac0b..d6af74fb 100644 --- a/catchtest/test_permutations.cpp +++ b/catchtest/test_permutations.cpp @@ -47,3 +47,17 @@ TEST_CASE("permutations: binds to lvalues, moves rvalues", "[permutations]") { REQUIRE(bi.was_moved_from()); } } + +namespace itertest { + bool operator<(const SolidInt& lhs, const SolidInt& rhs) { + return lhs.getint() < rhs.getint(); + } +} + +TEST_CASE("permutations doesn't move or copy elements of iterable", + "[permutations]") { + constexpr itertest::SolidInt arr[] = {{1}, {0}, {2}}; + for (auto&& st : permutations(arr)) { + (void)st; + } +} From fac55bf7f5fa6e6a759670b816993d9d98db6523 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 8 Jan 2015 22:46:24 -0500 Subject: [PATCH 0736/1866] powerset iter inherits from std iterator --- powerset.hpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/powerset.hpp b/powerset.hpp index be8e60a8..b8f7bbae 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -34,7 +34,10 @@ namespace iter { } } - class Iterator { + class Iterator + : public std::iterator< + std::input_iterator_tag, iterator_deref> + { private: std::size_t container_size; std::size_t list_size = 0; @@ -64,7 +67,7 @@ namespace iter { return *this; } - auto operator*() -> decltype(*inner_iters[0]) { + iterator_deref operator*() { return *(inner_iters[list_size]); } From 42ed54e3c6b7339b77960f46a31d62a126696647 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 8 Jan 2015 22:46:47 -0500 Subject: [PATCH 0737/1866] powerset test with small test case --- catchtest/test_powerset.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 catchtest/test_powerset.cpp diff --git a/catchtest/test_powerset.cpp b/catchtest/test_powerset.cpp new file mode 100644 index 00000000..18408ba6 --- /dev/null +++ b/catchtest/test_powerset.cpp @@ -0,0 +1,23 @@ +#include + +#include "helpers.hpp" + +#include +#include +#include + +#include "catch.hpp" + +using iter::powerset; +using IntPermSet = std::multiset>; + +TEST_CASE("powerset: basic test, [1, 2, 3]", "[powerset]") { + const std::vector ns = {1, 2, 3}; + IntPermSet v; + for (auto&& st : powerset(ns)) { + v.emplace(std::begin(st), std::end(st)); + } + + const IntPermSet vc = { {}, {1}, {2}, {3,}, {1,2}, {1,3}, {2,3}, {1,2,3} }; + REQUIRE( v == vc ); +} From 4dc1948342861cab0ab38380df6de9fd09ea1221 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 8 Jan 2015 22:47:12 -0500 Subject: [PATCH 0738/1866] builds powerset test --- catchtest/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index daae60a4..3ce37300 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -31,6 +31,7 @@ progs = Split( groupby imap permutations + powerset ''' ) From f572c761e5b843d347c82e84d56c0f8634aae7eb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 8 Jan 2015 22:47:45 -0500 Subject: [PATCH 0739/1866] adds powerset postfix ++ --- powerset.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/powerset.hpp b/powerset.hpp index b8f7bbae..c6658526 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -67,6 +67,12 @@ namespace iter { return *this; } + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + iterator_deref operator*() { return *(inner_iters[list_size]); } From aea4229d723e3a419265a296dc34e73b4d4e8847 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 8 Jan 2015 22:47:59 -0500 Subject: [PATCH 0740/1866] adds powerset iter == --- powerset.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/powerset.hpp b/powerset.hpp index c6658526..49ab9d3d 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -80,6 +80,10 @@ namespace iter { bool operator != (const Iterator&) { return not_done; } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } }; Iterator begin() { From e03bddcd7c2817cd32910a9ed3dea9ffa7a51c04 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 8 Jan 2015 22:49:28 -0500 Subject: [PATCH 0741/1866] moves CombinatorType into PowerSetter as typealias --- powerset.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/powerset.hpp b/powerset.hpp index 49ab9d3d..8a39cbfa 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -12,12 +12,12 @@ #include namespace iter { - template (), 0))> + template class Powersetter { private: Container container; + using CombinatorType = + decltype(combinations(std::declval(), 0)); std::vector combinators; public: From e489e350e5fb0ec95b2ee1ffe86559a68190034f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 10 Jan 2015 17:01:26 -0500 Subject: [PATCH 0742/1866] marks powerset iter != as const --- powerset.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerset.hpp b/powerset.hpp index 8a39cbfa..5ad8afc2 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -77,7 +77,7 @@ namespace iter { return *(inner_iters[list_size]); } - bool operator != (const Iterator&) { + bool operator != (const Iterator&) const { return not_done; } From 78f61e5859380d5d2fa8d23232d19794977eed27 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 10 Jan 2015 17:10:20 -0500 Subject: [PATCH 0743/1866] adds missing return *this to BasicIterable's ++ --- catchtest/helpers.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/catchtest/helpers.hpp b/catchtest/helpers.hpp index bb034e16..d3dacfa6 100644 --- a/catchtest/helpers.hpp +++ b/catchtest/helpers.hpp @@ -100,6 +100,7 @@ class BasicIterable { Iterator& operator++() { ++this->p; + return *this; } T& operator*() { From aa5a5c478f7b7b5f767e6008189d52ab52f26d09 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 10 Jan 2015 17:14:24 -0500 Subject: [PATCH 0744/1866] tests powerset with empy iterable --- catchtest/test_powerset.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/catchtest/test_powerset.cpp b/catchtest/test_powerset.cpp index 18408ba6..99eeea06 100644 --- a/catchtest/test_powerset.cpp +++ b/catchtest/test_powerset.cpp @@ -21,3 +21,12 @@ TEST_CASE("powerset: basic test, [1, 2, 3]", "[powerset]") { const IntPermSet vc = { {}, {1}, {2}, {3,}, {1,2}, {1,3}, {2,3}, {1,2,3} }; REQUIRE( v == vc ); } + +TEST_CASE("powerset: empty sequence gives only empty set", "[powerset]") { + const std::vector ns = {}; + auto ps = powerset(ns); + auto it = std::begin(ps); + REQUIRE( std::begin(*it) == std::end(*it) ); // it's empty + ++it; + REQUIRE( it == std::end(ps) ); +} From dc58fce738833a6e70e5c2d5c3b819897a60b555 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 10 Jan 2015 17:14:43 -0500 Subject: [PATCH 0745/1866] tests powerset for move/bind correctness --- catchtest/test_powerset.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/catchtest/test_powerset.cpp b/catchtest/test_powerset.cpp index 99eeea06..7c22d558 100644 --- a/catchtest/test_powerset.cpp +++ b/catchtest/test_powerset.cpp @@ -30,3 +30,24 @@ TEST_CASE("powerset: empty sequence gives only empty set", "[powerset]") { ++it; REQUIRE( it == std::end(ps) ); } + +TEST_CASE("powerset: binds to lvalues, moves rvalues", "[powerset]") { + itertest::BasicIterable bi{1, 2}; + SECTION("binds to lvalues") { + powerset(bi); + REQUIRE_FALSE(bi.was_moved_from()); + } + SECTION("moves rvalues") { + powerset(std::move(bi)); + REQUIRE(bi.was_moved_from()); + } +} + +TEST_CASE("powerset: doesn't move or copy elements of iterable", "[powerset]"){ + constexpr itertest::SolidInt arr[] = {{1}, {0}, {2}}; + for (auto&& st : powerset(arr)) { + for (auto&& i : st) { + (void)i; + } + } +} From 401d9a03edf0ff394e073707ca0780d373943d9f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 10 Jan 2015 21:59:12 -0500 Subject: [PATCH 0746/1866] make combinations iterators assignable uses pointers instead of references --- combinations.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/combinations.hpp b/combinations.hpp index e05fb957..089d0abc 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -43,14 +43,14 @@ namespace iter { public std::iterator { private: - Container& items; + typename std::remove_reference::type *container_p; std::vector> indicies; bool not_done = true; public: - Iterator(Container& i, std::size_t n) - : items(i), - indicies(n) + Iterator(Container& in_container, std::size_t n) + : container_p{&in_container}, + indicies{n} { if (n == 0) { not_done = false; @@ -58,9 +58,9 @@ namespace iter { } size_t inc = 0; for (auto& iter : this->indicies) { - auto it = std::begin(this->items); - dumb_advance(it, std::end(this->items), inc); - if (it != std::end(this->items)) { + auto it = std::begin(*this->container_p); + dumb_advance(it, std::end(*this->container_p), inc); + if (it != std::end(*this->container_p)) { iter = it; ++inc; } else { @@ -92,7 +92,7 @@ namespace iter { this->indicies.rbegin(),iter); if (!(dumb_next(*iter, dist) != - std::end(this->items))) { + std::end(*this->container_p))) { if ( (iter + 1) != indicies.rend()) { size_t inc = 1; for (auto down = iter; From 0e335cfb07a4fc3cec160b98aa854e5a5aab8a82 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 10 Jan 2015 22:09:54 -0500 Subject: [PATCH 0747/1866] make comb_w_repl iterators assignable same as combinations(), uses a pointer to the container instead of binding a reference to it. --- combinations_with_replacement.hpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index 615da8b8..4b521e76 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -50,15 +50,14 @@ namespace iter { CombIteratorDeref> { private: - Container& items; + typename std::remove_reference::type *container_p; std::vector> indicies; bool not_done; public: - Iterator( - Container& container, std::size_t n) - : items(container), - indicies(n, std::begin(items)), + Iterator(Container& in_container, std::size_t n) + : container_p{&in_container}, + indicies(n, std::begin(in_container)), not_done{n != 0} { } @@ -76,7 +75,7 @@ namespace iter { iter != indicies.rend(); ++iter) { ++(*iter); - if (!(*iter != std::end(items))) { + if (!(*iter != std::end(*this->container_p))) { if ( (iter + 1) != indicies.rend()) { for (auto down = iter; down != indicies.rbegin()-1; From bfdef91d40bf69737bb48e9a6046338245d48d94 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 10 Jan 2015 22:11:40 -0500 Subject: [PATCH 0748/1866] powerset lazily make combinators the previous implementation created a vector of combinators up front. This approach isn't terrible, but this version has less code and only allocates one Combinator at a time. --- iterbase.hpp | 11 ++++++++ powerset.hpp | 78 ++++++++++++++++++++++------------------------------ 2 files changed, 44 insertions(+), 45 deletions(-) diff --git a/iterbase.hpp b/iterbase.hpp index 0ce5d441..d426af91 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -45,6 +45,17 @@ namespace iter { return it; } + template + Distance dumb_size(Container&& container) { + Distance d{0}; + for (auto it = std::begin(container), end = std::end(container); + it != end; + ++it) { + ++d; + } + return d; + } + // iterator_type is the type of C's iterator template using iterator_type = diff --git a/powerset.hpp b/powerset.hpp index 5ad8afc2..8e3b310c 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -1,12 +1,11 @@ -#ifndef POWERSET_HPP_ -#define POWERSET_HPP_ +#ifndef ITER_POWERSET_HPP_ +#define ITER_POWERSET_HPP_ #include "iterbase.hpp" #include "combinations.hpp" -#include "enumerate.hpp" #include -#include +#include #include #include #include @@ -19,51 +18,40 @@ namespace iter { using CombinatorType = decltype(combinations(std::declval(), 0)); - std::vector combinators; public: Powersetter(Container in_container) : container(std::forward(in_container)) - { - combinators.push_back(combinations(this->container, 0)); - std::size_t i = 1; - for (auto iter = std::begin(this->container), - end = std::end(this->container); - iter != end; - ++iter, ++i) { - combinators.push_back(combinations(this->container, i)); - } - } + { } - class Iterator + class Iterator : public std::iterator< - std::input_iterator_tag, iterator_deref> + std::input_iterator_tag, CombinatorType> { private: - std::size_t container_size; - std::size_t list_size = 0; - bool not_done = true; + Container& container; + std::size_t set_size; + std::unique_ptr comb; + iterator_type comb_iter; + iterator_type comb_end; - std::vector& combinators; - std::vector> inner_iters; public: - Iterator(std::vector& combs) - : container_size{combs.size() - 1}, - combinators(combs) - { - for (auto& comb : combinators) { - inner_iters.push_back(std::begin(comb)); - } - } + Iterator(Container& in_container, std::size_t sz) + : container{in_container}, + set_size{sz}, + comb{new CombinatorType(combinations(in_container, sz))}, + comb_iter{std::begin(*comb)}, + comb_end{std::end(*comb)} + { } Iterator& operator++() { - ++inner_iters[list_size]; - if (!(inner_iters[list_size] != inner_iters[list_size])) { - ++list_size; - } - if (container_size < list_size) { - not_done = false; + ++this->comb_iter; + if (this->comb_iter == this->comb_end) { + ++this->set_size; + this->comb.reset(new CombinatorType(combinations( + this->container, this->set_size))); + this->comb_iter = std::begin(*this->comb); + this->comb_end = std::end(*this->comb); } - return *this; } @@ -74,24 +62,24 @@ namespace iter { } iterator_deref operator*() { - return *(inner_iters[list_size]); + return *this->comb_iter; } - bool operator != (const Iterator&) const { - return not_done; + bool operator != (const Iterator& other) const { + return !(*this == other); } bool operator==(const Iterator& other) const { - return !(*this != other); + return this->set_size == other.set_size; } - }; + }; Iterator begin() { - return {this->combinators}; + return {this->container, 0}; } Iterator end() { - return {this->combinators}; + return {this->container, dumb_size(this->container) + 1}; } }; @@ -106,4 +94,4 @@ namespace iter { return {il}; } } -#endif // #ifndef POWERSET_HPP_ +#endif From cd447fe6ad38a27ef00924aa7931f55131531392 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 10 Jan 2015 22:26:24 -0500 Subject: [PATCH 0749/1866] make powerset iterators assignable pointer to container instead of reference --- powerset.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/powerset.hpp b/powerset.hpp index 8e3b310c..69abf4fa 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace iter { template @@ -28,7 +29,7 @@ namespace iter { std::input_iterator_tag, CombinatorType> { private: - Container& container; + typename std::remove_reference::type *container_p; std::size_t set_size; std::unique_ptr comb; iterator_type comb_iter; @@ -36,7 +37,7 @@ namespace iter { public: Iterator(Container& in_container, std::size_t sz) - : container{in_container}, + : container_p{&in_container}, set_size{sz}, comb{new CombinatorType(combinations(in_container, sz))}, comb_iter{std::begin(*comb)}, @@ -48,7 +49,7 @@ namespace iter { if (this->comb_iter == this->comb_end) { ++this->set_size; this->comb.reset(new CombinatorType(combinations( - this->container, this->set_size))); + *this->container_p, this->set_size))); this->comb_iter = std::begin(*this->comb); this->comb_end = std::end(*this->comb); } From dcfe1ea141c95c425f4d4875a73d3ddef411d4e4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 19 Jan 2015 14:17:49 -0500 Subject: [PATCH 0750/1866] product iterator inherits from std::iterator --- product.hpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/product.hpp b/product.hpp index 4b14353d..2aceda83 100644 --- a/product.hpp +++ b/product.hpp @@ -7,7 +7,6 @@ #include #include - namespace iter { template class Productor; @@ -27,6 +26,9 @@ namespace iter { template friend class Productor; + using ProdIterDeref = std::tuple< + iterator_deref, iterator_deref...>; + private: Container container; Productor rest_products; @@ -36,7 +38,9 @@ namespace iter { { } public: - class Iterator { + class Iterator + : public std::iterator + { private: using RestIter = typename Productor::Iterator; @@ -76,12 +80,7 @@ namespace iter { this->rest_iter != other.rest_iter); } - auto operator*() -> - decltype(std::tuple_cat( - std::tuple>{ - *this->iter}, - *this->rest_iter)) - { + ProdIterDeref operator*() { return std::tuple_cat( std::tuple>{ *this->iter}, @@ -106,7 +105,9 @@ namespace iter { template <> class Productor<> { public: - class Iterator { + class Iterator + : public std::iterator> + { public: constexpr static const bool is_base_iter = true; From bec181eae5347a623ed5fce909a1a800a2f74706 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 19 Jan 2015 14:18:08 -0500 Subject: [PATCH 0751/1866] adds basic product test --- catchtest/test_product.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 catchtest/test_product.cpp diff --git a/catchtest/test_product.cpp b/catchtest/test_product.cpp new file mode 100644 index 00000000..91e57c63 --- /dev/null +++ b/catchtest/test_product.cpp @@ -0,0 +1,27 @@ +#include + +#include "helpers.hpp" + +#include +#include +#include + +#include "catch.hpp" + +using iter::product; +using Vec = const std::vector; + +TEST_CASE("product: basic test, two vectors", "[product]") { + using ResType = std::vector>; + using TP = std::tuple; + + Vec n1 = {0, 1}; + Vec n2 = {0, 1, 2}; + + auto p = product(n1, n2); + ResType v(std::begin(p), std::end(p)); + ResType vc = {TP{0,0}, TP{0,1}, TP{0,2}, TP{1,0}, TP{1,1}, TP{1,2}}; + + REQUIRE( v == vc ); +} + From 8114a5a518dc2586f42e2a15f81803c24b7c0955 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 19 Jan 2015 14:25:30 -0500 Subject: [PATCH 0752/1866] adds == and postfix ++ to product iter --- product.hpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/product.hpp b/product.hpp index 2aceda83..b966d581 100644 --- a/product.hpp +++ b/product.hpp @@ -74,12 +74,23 @@ namespace iter { return *this; } + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + bool operator!=(const Iterator& other) const { return this->iter != other.iter && (RestIter::is_base_iter || this->rest_iter != other.rest_iter); } + bool operator==(const Iterator& other) const { + return !(*this != other); + } + + ProdIterDeref operator*() { return std::tuple_cat( std::tuple>{ @@ -121,11 +132,21 @@ namespace iter { return *this; } + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + // see note in zip about base case operator!= bool operator!=(const Iterator&) const { return false; } + bool operator==(const Iterator& other) const { + return !(*this != other); + } + std::tuple<> operator*() const { return std::tuple<>{}; } From 21461ad662b887d45ccbc799e8cfe1526de1c63f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 19 Jan 2015 14:26:44 -0500 Subject: [PATCH 0753/1866] tests product with empty sequences --- catchtest/test_product.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/catchtest/test_product.cpp b/catchtest/test_product.cpp index 91e57c63..074b1d85 100644 --- a/catchtest/test_product.cpp +++ b/catchtest/test_product.cpp @@ -25,3 +25,23 @@ TEST_CASE("product: basic test, two vectors", "[product]") { REQUIRE( v == vc ); } +TEST_CASE("product: empty when any iterable is empty", "[product]") { + Vec n1 = {0, 1}; + Vec n2 = {0, 1, 2}; + Vec emp = {}; + + SECTION("first iterable is empty") { + auto p = product(emp, n1, n2); + REQUIRE( std::begin(p) == std::end(p) ); + } + + SECTION("middle iterable is empty") { + auto p = product(n1, emp, n2); + REQUIRE( std::begin(p) == std::end(p) ); + } + + SECTION("last iterable is empty") { + auto p = product(n1, n2, emp); + REQUIRE( std::begin(p) == std::end(p) ); + } +} From e9832207c5def75942adc59f82f1fa2f76508d50 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 19 Jan 2015 14:27:14 -0500 Subject: [PATCH 0754/1866] builds product catch test --- catchtest/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index 3ce37300..ce88d2a3 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -32,6 +32,7 @@ progs = Split( imap permutations powerset + product ''' ) From 2d8416ede6762dd51a645ee7290fe8a02346e560 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 19 Jan 2015 18:05:34 -0500 Subject: [PATCH 0755/1866] Adds test with a single iterable --- catchtest/test_product.cpp | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/catchtest/test_product.cpp b/catchtest/test_product.cpp index 074b1d85..e968369d 100644 --- a/catchtest/test_product.cpp +++ b/catchtest/test_product.cpp @@ -11,16 +11,17 @@ using iter::product; using Vec = const std::vector; -TEST_CASE("product: basic test, two vectors", "[product]") { - using ResType = std::vector>; - using TP = std::tuple; +TEST_CASE("product: basic test, two sequences", "[product]") { + using TP = std::tuple; + using ResType = std::vector; Vec n1 = {0, 1}; - Vec n2 = {0, 1, 2}; + const std::string s{"abc"}; - auto p = product(n1, n2); + auto p = product(n1, s); ResType v(std::begin(p), std::end(p)); - ResType vc = {TP{0,0}, TP{0,1}, TP{0,2}, TP{1,0}, TP{1,1}, TP{1,2}}; + ResType vc = {TP{0,'a'}, TP{0,'b'}, TP{0,'c'}, + TP{1,'a'}, TP{1,'b'}, TP{1,'c'}}; REQUIRE( v == vc ); } @@ -45,3 +46,15 @@ TEST_CASE("product: empty when any iterable is empty", "[product]") { REQUIRE( std::begin(p) == std::end(p) ); } } + +TEST_CASE("product: single iterable", "[product]") { + const std::string s{"ab"}; + using TP = std::tuple; + using ResType = const std::vector; + + auto p = product(s); + ResType v(std::begin(p), std::end(p)); + ResType vc = {TP{'a'}, TP{'b'}}; + + REQUIRE( v == vc ); +} From a3ebb61327e0f283fb20527ff2be261c1fa6f464 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 19 Jan 2015 18:10:04 -0500 Subject: [PATCH 0756/1866] tests product with three iterables --- catchtest/test_product.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/catchtest/test_product.cpp b/catchtest/test_product.cpp index e968369d..e10e4a23 100644 --- a/catchtest/test_product.cpp +++ b/catchtest/test_product.cpp @@ -26,6 +26,28 @@ TEST_CASE("product: basic test, two sequences", "[product]") { REQUIRE( v == vc ); } +TEST_CASE("product: three sequences", "[product]") { + using TP = std::tuple ; + using ResType = const std::vector; + + Vec n1 = {0, 1}; + const std::string s{"ab"}; + Vec n2 = {2}; + + auto p = product(n1, s, n2); + ResType v(std::begin(p), std::end(p)); + + ResType vc = { + TP{0, 'a', 2}, + TP{0, 'b', 2}, + TP{1, 'a', 2}, + TP{1, 'b', 2} + }; + + REQUIRE( v == vc ); +} + + TEST_CASE("product: empty when any iterable is empty", "[product]") { Vec n1 = {0, 1}; Vec n2 = {0, 1, 2}; From 0d654b3c0ecca945e6ed9f3ef62b2136dfb0060b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 19 Jan 2015 18:14:58 -0500 Subject: [PATCH 0757/1866] tests that product doesn't move or copy elements --- catchtest/test_product.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/catchtest/test_product.cpp b/catchtest/test_product.cpp index e10e4a23..94ce4906 100644 --- a/catchtest/test_product.cpp +++ b/catchtest/test_product.cpp @@ -80,3 +80,10 @@ TEST_CASE("product: single iterable", "[product]") { REQUIRE( v == vc ); } + +TEST_CASE("product: doesn't move or copy elements of iterable", "[product]") { + constexpr itertest::SolidInt arr[] = {{1}, {0}, {2}}; + for (auto&& t : product(arr)) { + (void)std::get<0>(t); + } +} From 1be88e0e5e9f821b443024b9763df3191e0d5e3d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 19 Jan 2015 19:32:37 -0500 Subject: [PATCH 0758/1866] tests that product moves and binds correctly --- catchtest/test_product.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/catchtest/test_product.cpp b/catchtest/test_product.cpp index 94ce4906..1b46ff3b 100644 --- a/catchtest/test_product.cpp +++ b/catchtest/test_product.cpp @@ -81,6 +81,23 @@ TEST_CASE("product: single iterable", "[product]") { REQUIRE( v == vc ); } +TEST_CASE("product: binds to lvalues and moves rvalues", "[product]") { + itertest::BasicIterable bi{'x', 'y'}; + itertest::BasicIterable bi2{0, 1}; + + SECTION("First ref'd, second moved") { + product(bi, std::move(bi2)); + REQUIRE_FALSE( bi.was_moved_from() ); + REQUIRE( bi2.was_moved_from() ); + } + + SECTION("First moved, second ref'd") { + product(std::move(bi), bi2); + REQUIRE( bi.was_moved_from() ); + REQUIRE_FALSE( bi2.was_moved_from() ); + } +} + TEST_CASE("product: doesn't move or copy elements of iterable", "[product]") { constexpr itertest::SolidInt arr[] = {{1}, {0}, {2}}; for (auto&& t : product(arr)) { From ff54629f5aa41e6d56b59731f120395301aa4ae4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 19 Jan 2015 20:02:06 -0500 Subject: [PATCH 0759/1866] tests empty product() --- catchtest/test_product.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/catchtest/test_product.cpp b/catchtest/test_product.cpp index 1b46ff3b..3e160d0f 100644 --- a/catchtest/test_product.cpp +++ b/catchtest/test_product.cpp @@ -81,6 +81,15 @@ TEST_CASE("product: single iterable", "[product]") { REQUIRE( v == vc ); } +TEST_CASE("product: no arguments gives one empty tuple", "[product") { + auto p = product(); + auto it = std::begin(p); + REQUIRE( it != std::end(p) ); + REQUIRE( *it == std::make_tuple() ); + ++it; + REQUIRE( it == std::end(p) ); +} + TEST_CASE("product: binds to lvalues and moves rvalues", "[product]") { itertest::BasicIterable bi{'x', 'y'}; itertest::BasicIterable bi2{0, 1}; From 04a2da4a13ab9f28a407777fc83f8477e7ea8888 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 19 Jan 2015 20:02:19 -0500 Subject: [PATCH 0760/1866] adds special case for product() since it is weird --- product.hpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/product.hpp b/product.hpp index b966d581..93c977f2 100644 --- a/product.hpp +++ b/product.hpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace iter { template @@ -121,11 +122,10 @@ namespace iter { { public: constexpr static const bool is_base_iter = true; - - Iterator() { } Iterator(const Iterator&) { } Iterator& operator=(const Iterator&) { return *this; } + Iterator() { } void reset() { } Iterator& operator++() { @@ -165,6 +165,10 @@ namespace iter { Productor product(Containers&&... containers) { return {std::forward(containers)...}; } + + constexpr std::array, 1> product() { + return {{}}; + } } -#endif // #ifndef ITER_PRODUCT_HPP_ +#endif From ddf7e6e82bebdd42af68a9d5b9c5e72a93e0d44a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 19 Jan 2015 20:03:21 -0500 Subject: [PATCH 0761/1866] Removes unecessary explicit ctor and operator= --- product.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/product.hpp b/product.hpp index 93c977f2..c40909f8 100644 --- a/product.hpp +++ b/product.hpp @@ -122,10 +122,7 @@ namespace iter { { public: constexpr static const bool is_base_iter = true; - Iterator(const Iterator&) { } - Iterator& operator=(const Iterator&) { return *this; } - Iterator() { } void reset() { } Iterator& operator++() { From b244969c402cd87e1165887ac4e9be4b96628d7a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 19 Jan 2015 20:06:06 -0500 Subject: [PATCH 0762/1866] adds devel catch.hpp to allow printing of tuples --- catchtest/catch.hpp | 943 +++++++++++++++++++++++++++++++------------- 1 file changed, 676 insertions(+), 267 deletions(-) diff --git a/catchtest/catch.hpp b/catchtest/catch.hpp index 6b8dfb5e..c79324cf 100644 --- a/catchtest/catch.hpp +++ b/catchtest/catch.hpp @@ -1,6 +1,6 @@ /* - * CATCH v1.0 build 53 (master branch) - * Generated: 2014-08-20 08:08:19.533804 + * CATCH v1.1 build 13 (develop branch) + * Generated: 2014-12-30 18:47:08.984634 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. @@ -33,11 +33,11 @@ #pragma GCC diagnostic ignored "-Wpadded" #endif -#ifdef CATCH_CONFIG_MAIN -# define CATCH_CONFIG_RUNNER +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL #endif -#ifdef CATCH_CONFIG_RUNNER +#ifdef CATCH_IMPL # ifndef CLARA_CONFIG_MAIN # define CLARA_CONFIG_MAIN_NOT_DEFINED # define CLARA_CONFIG_MAIN @@ -135,6 +135,10 @@ // Visual C++ #ifdef _MSC_VER +#if (_MSC_VER >= 1600) +#define CATCH_CONFIG_CPP11_NULLPTR +#endif + #if (_MSC_VER >= 1310 ) // (VC++ 7.0+) //#define CATCH_CONFIG_SFINAE // Not confirmed #endif @@ -176,8 +180,16 @@ namespace Catch { class NonCopyable { - NonCopyable( NonCopyable const& ); - void operator = ( NonCopyable const& ); +#ifdef CATCH_CPP11_OR_GREATER + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; +#else + NonCopyable( NonCopyable const& info ); + NonCopyable& operator = ( NonCopyable const& ); +#endif + protected: NonCopyable() {} virtual ~NonCopyable(); @@ -215,6 +227,7 @@ namespace Catch { void toLowerInPlace( std::string& s ); std::string toLower( std::string const& s ); std::string trim( std::string const& str ); + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); struct pluralise { pluralise( std::size_t count, std::string const& label ); @@ -467,7 +480,7 @@ namespace Catch { struct ITestCaseRegistry { virtual ~ITestCaseRegistry(); virtual std::vector const& getAllTests() const = 0; - virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases ) const = 0; + virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const = 0; }; } @@ -603,7 +616,9 @@ namespace Catch { Exception = 0x100 | FailureBit, ThrewException = Exception | 1, - DidntThrowException = Exception | 2 + DidntThrowException = Exception | 2, + + FatalErrorCondition = 0x200 | FailureBit }; }; @@ -1034,9 +1049,49 @@ inline id performOptionalSelector( id obj, SEL sel ) { #endif +#ifdef CATCH_CPP11_OR_GREATER +#include +#include +#endif + namespace Catch { + +// Why we're here. +template +std::string toString( T const& value ); + +// Built in overloads + +std::string toString( std::string const& value ); +std::string toString( std::wstring const& value ); +std::string toString( const char* const value ); +std::string toString( char* const value ); +std::string toString( const wchar_t* const value ); +std::string toString( wchar_t* const value ); +std::string toString( int value ); +std::string toString( unsigned long value ); +std::string toString( unsigned int value ); +std::string toString( const double value ); +std::string toString( const float value ); +std::string toString( bool value ); +std::string toString( char value ); +std::string toString( signed char value ); +std::string toString( unsigned char value ); + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ); +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ); + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); + std::string toString( NSObject* const& nsObject ); +#endif + namespace Detail { + extern std::string unprintableString; + // SFINAE is currently disabled by default for all compilers. // If the non SFINAE version of IsStreamInsertable is ambiguous for you // and your compiler supports SFINAE, try #defining CATCH_CONFIG_SFINAE @@ -1077,10 +1132,38 @@ namespace Detail { #endif +#if defined(CATCH_CPP11_OR_GREATER) + template::value + > + struct EnumStringMaker + { + static std::string convert( T const& ) { return unprintableString; } + }; + + template + struct EnumStringMaker + { + static std::string convert( T const& v ) + { + return ::Catch::toString( + static_cast::type>(v) + ); + } + }; +#endif template struct StringMakerBase { +#if defined(CATCH_CPP11_OR_GREATER) + template + static std::string convert( T const& v ) + { + return EnumStringMaker::convert( v ); + } +#else template - static std::string convert( T const& ) { return "{?}"; } + static std::string convert( T const& ) { return unprintableString; } +#endif }; template<> @@ -1102,9 +1185,6 @@ namespace Detail { } // end namespace Detail -template -std::string toString( T const& value ); - template struct StringMaker : Detail::StringMakerBase::value> {}; @@ -1135,12 +1215,59 @@ namespace Detail { std::string rangeToString( InputIterator first, InputIterator last ); } +//template +//struct StringMaker > { +// static std::string convert( std::vector const& v ) { +// return Detail::rangeToString( v.begin(), v.end() ); +// } +//}; + template -struct StringMaker > { - static std::string convert( std::vector const& v ) { - return Detail::rangeToString( v.begin(), v.end() ); +std::string toString( std::vector const& v ) { + return Detail::rangeToString( v.begin(), v.end() ); +} + +#ifdef CATCH_CPP11_OR_GREATER +//toString for tuples + +namespace TupleDetail { + template< + typename Tuple, + std::size_t N = 0, + bool = (N < std::tuple_size::value) + > + struct ElementPrinter { + static void print( const Tuple& tuple, std::ostream& os ) + { + os << ( N ? ", " : " " ) + << Catch::toString(std::get(tuple)); + ElementPrinter::print(tuple,os); + } + }; + + template< + typename Tuple, + std::size_t N + > + struct ElementPrinter { + static void print( const Tuple&, std::ostream& ) {} + }; + +} + +template +struct StringMaker> { + + static std::string convert( const std::tuple& tuple ) + { + std::ostringstream os; + os << '{'; + TupleDetail::ElementPrinter>::print( tuple, os ); + os << " }"; + return os.str(); } }; +#endif namespace Detail { template @@ -1161,44 +1288,15 @@ std::string toString( T const& value ) { return StringMaker::convert( value ); } -// Built in overloads - -std::string toString( std::string const& value ); -std::string toString( std::wstring const& value ); -std::string toString( const char* const value ); -std::string toString( char* const value ); -std::string toString( const wchar_t* const value ); -std::string toString( wchar_t* const value ); -std::string toString( int value ); -std::string toString( unsigned long value ); -std::string toString( unsigned int value ); -std::string toString( const double value ); -std::string toString( const float value ); -std::string toString( bool value ); -std::string toString( char value ); -std::string toString( signed char value ); -std::string toString( unsigned char value ); - -#ifdef CATCH_CONFIG_CPP11_NULLPTR -std::string toString( std::nullptr_t ); -#endif - -#ifdef __OBJC__ - std::string toString( NSString const * const& nsstring ); - std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); - std::string toString( NSObject* const& nsObject ); -#endif - namespace Detail { template std::string rangeToString( InputIterator first, InputIterator last ) { std::ostringstream oss; oss << "{ "; if( first != last ) { - oss << toString( *first ); - for( ++first ; first != last ; ++first ) { - oss << ", " << toString( *first ); - } + oss << Catch::toString( *first ); + for( ++first ; first != last ; ++first ) + oss << ", " << Catch::toString( *first ); } oss << " }"; return oss.str(); @@ -1395,6 +1493,8 @@ namespace Catch { virtual std::string getCurrentTestName() const = 0; virtual const AssertionResult* getLastResult() const = 0; + + virtual void handleFatalErrorCondition( std::string const& message ) = 0; }; IResultCapture& getResultCapture(); @@ -1575,7 +1675,7 @@ namespace Catch { std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \ __catchResult \ .setLhs( Catch::toString( arg ) ) \ - .setRhs( matcherAsString == "{?}" ? #matcher : matcherAsString ) \ + .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ .setOp( "matches" ) \ .setResultType( ::Catch::Matchers::matcher.match( arg ) ); \ __catchResult.captureExpression(); \ @@ -1636,6 +1736,9 @@ namespace Catch { bool allPassed() const { return failed == 0 && failedButOk == 0; } + bool allOk() const { + return failed == 0; + } std::size_t passed; std::size_t failed; @@ -1688,7 +1791,7 @@ namespace Catch { public: Timer() : m_ticks( 0 ) {} void start(); - unsigned int getElapsedNanoseconds() const; + unsigned int getElapsedMicroseconds() const; unsigned int getElapsedMilliseconds() const; double getElapsedSeconds() const; @@ -1702,7 +1805,7 @@ namespace Catch { namespace Catch { - class Section { + class Section : NonCopyable { public: Section( SectionInfo const& info ); ~Section(); @@ -1711,15 +1814,6 @@ namespace Catch { operator bool() const; private: -#ifdef CATCH_CPP11_OR_GREATER - Section( Section const& ) = delete; - Section( Section && ) = delete; - Section& operator = ( Section const& ) = delete; - Section& operator = ( Section && ) = delete; -#else - Section( Section const& info ); - Section& operator = ( Section const& ); -#endif SectionInfo m_info; std::string m_name; @@ -2694,7 +2788,7 @@ return @ desc; \ #endif -#ifdef CATCH_CONFIG_RUNNER +#ifdef CATCH_IMPL // #included from: internal/catch_impl.hpp #define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED @@ -2962,6 +3056,11 @@ namespace Catch { Always, Never }; }; + struct RunTests { enum InWhatOrder { + InDeclarationOrder, + InLexicographicalOrder, + InRandomOrder + }; }; class TestSpec; @@ -2979,6 +3078,8 @@ namespace Catch { virtual bool showInvisibles() const = 0; virtual ShowDurations::OrNot showDurations() const = 0; virtual TestSpec const& testSpec() const = 0; + virtual RunTests::InWhatOrder runOrder() const = 0; + virtual unsigned int rngSeed() const = 0; }; } @@ -3004,12 +3105,16 @@ namespace Catch { private: bool isOwned; }; + + std::ostream& cout(); + std::ostream& cerr(); } #include #include #include #include +#include #ifndef CATCH_CONFIG_CONSOLE_WIDTH #define CATCH_CONFIG_CONSOLE_WIDTH 80 @@ -3030,9 +3135,11 @@ namespace Catch { showHelp( false ), showInvisibles( false ), abortAfter( -1 ), + rngSeed( 0 ), verbosity( Verbosity::Normal ), warnings( WarnAbout::Nothing ), - showDurations( ShowDurations::DefaultForReporter ) + showDurations( ShowDurations::DefaultForReporter ), + runOrder( RunTests::InDeclarationOrder ) {} bool listTests; @@ -3047,10 +3154,12 @@ namespace Catch { bool showInvisibles; int abortAfter; + unsigned int rngSeed; Verbosity::Level verbosity; WarnAbout::What warnings; ShowDurations::OrNot showDurations; + RunTests::InWhatOrder runOrder; std::string reporterName; std::string outputFilename; @@ -3068,12 +3177,12 @@ namespace Catch { public: Config() - : m_os( std::cout.rdbuf() ) + : m_os( Catch::cout().rdbuf() ) {} Config( ConfigData const& data ) : m_data( data ), - m_os( std::cout.rdbuf() ) + m_os( Catch::cout().rdbuf() ) { if( !data.testsOrTags.empty() ) { TestSpecParser parser( ITagAliasRegistry::get() ); @@ -3084,7 +3193,7 @@ namespace Catch { } virtual ~Config() { - m_os.rdbuf( std::cout.rdbuf() ); + m_os.rdbuf( Catch::cout().rdbuf() ); m_stream.release(); } @@ -3106,7 +3215,7 @@ namespace Catch { bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } void setStreamBuf( std::streambuf* buf ) { - m_os.rdbuf( buf ? buf : std::cout.rdbuf() ); + m_os.rdbuf( buf ? buf : Catch::cout().rdbuf() ); } void useStream( std::string const& streamName ) { @@ -3132,6 +3241,8 @@ namespace Catch { virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; } + virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; } + virtual unsigned int rngSeed() const { return m_data.rngSeed; } private: ConfigData m_data; @@ -3760,7 +3871,7 @@ namespace Clara { m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) { if( other.m_floatingArg.get() ) - m_floatingArg = ArgAutoPtr( new Arg( *other.m_floatingArg ) ); + m_floatingArg.reset( new Arg( *other.m_floatingArg ) ); } CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { @@ -3788,7 +3899,7 @@ namespace Clara { ArgBuilder operator[]( UnpositionalTag ) { if( m_floatingArg.get() ) throw std::logic_error( "Only one unpositional argument can be added" ); - m_floatingArg = ArgAutoPtr( new Arg() ); + m_floatingArg.reset( new Arg() ); ArgBuilder builder( m_floatingArg.get() ); return builder; } @@ -3930,7 +4041,7 @@ namespace Clara { if( it == itEnd ) { if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) unusedTokens.push_back( token ); - else if( m_throwOnUnrecognisedTokens ) + else if( errors.empty() && m_throwOnUnrecognisedTokens ) errors.push_back( "unrecognised option: " + token.data ); } } @@ -4028,7 +4139,28 @@ namespace Catch { config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); else throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" ); - + } + inline void setOrder( ConfigData& config, std::string const& order ) { + if( startsWith( "declared", order ) ) + config.runOrder = RunTests::InDeclarationOrder; + else if( startsWith( "lexical", order ) ) + config.runOrder = RunTests::InLexicographicalOrder; + else if( startsWith( "random", order ) ) + config.runOrder = RunTests::InRandomOrder; + else + throw std::runtime_error( "Unrecognised ordering: '" + order + "'" ); + } + inline void setRngSeed( ConfigData& config, std::string const& seed ) { + if( seed == "time" ) { + config.rngSeed = static_cast( std::time(0) ); + } + else { + std::stringstream ss; + ss << seed; + ss >> config.rngSeed; + if( ss.fail() ) + throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" ); + } } inline void setVerbosity( ConfigData& config, int level ) { // !TBD: accept strings? @@ -4140,6 +4272,14 @@ namespace Catch { .describe( "list all reporters" ) .bind( &ConfigData::listReporters ); + cli["--order"] + .describe( "test case order (defaults to decl)" ) + .bind( &setOrder, "decl|lex|rand" ); + + cli["--rng-seed"] + .describe( "set a specific seed for random numbers" ) + .bind( &setRngSeed, "'time'|number" ); + return cli; } @@ -4313,10 +4453,6 @@ namespace Catch { namespace Catch { - namespace Detail { - struct IColourImpl; - } - struct Colour { enum Code { None = 0, @@ -4362,7 +4498,6 @@ namespace Catch { static void use( Code _colourCode ); private: - static Detail::IColourImpl* impl(); bool m_moved; }; @@ -4592,11 +4727,14 @@ namespace Catch virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; + // The return value indicates if the messages buffer should be cleared: virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; virtual void sectionEnded( SectionStats const& sectionStats ) = 0; virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; + + virtual void skipTest( TestCaseInfo const& testInfo ) = 0; }; struct IReporterFactory { @@ -4624,9 +4762,9 @@ namespace Catch { TestSpec testSpec = config.testSpec(); if( config.testSpec().hasFilters() ) - std::cout << "Matching test cases:\n"; + Catch::cout() << "Matching test cases:\n"; else { - std::cout << "All available test cases:\n"; + Catch::cout() << "All available test cases:\n"; testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); } @@ -4647,15 +4785,15 @@ namespace Catch { : Colour::None; Colour colourGuard( colour ); - std::cout << Text( testCaseInfo.name, nameAttr ) << std::endl; + Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; if( !testCaseInfo.tags.empty() ) - std::cout << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; + Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; } if( !config.testSpec().hasFilters() ) - std::cout << pluralise( matchedTests, "test case" ) << "\n" << std::endl; + Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl; else - std::cout << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl; + Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl; return matchedTests; } @@ -4671,7 +4809,7 @@ namespace Catch { ++it ) { matchedTests++; TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); - std::cout << testCaseInfo.name << std::endl; + Catch::cout() << testCaseInfo.name << std::endl; } return matchedTests; } @@ -4697,9 +4835,9 @@ namespace Catch { inline std::size_t listTags( Config const& config ) { TestSpec testSpec = config.testSpec(); if( config.testSpec().hasFilters() ) - std::cout << "Tags for matching test cases:\n"; + Catch::cout() << "Tags for matching test cases:\n"; else { - std::cout << "All available tags:\n"; + Catch::cout() << "All available tags:\n"; testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); } @@ -4733,14 +4871,14 @@ namespace Catch { .setInitialIndent( 0 ) .setIndent( oss.str().size() ) .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); - std::cout << oss.str() << wrapper << "\n"; + Catch::cout() << oss.str() << wrapper << "\n"; } - std::cout << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl; + Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl; return tagCounts.size(); } inline std::size_t listReporters( Config const& /*config*/ ) { - std::cout << "Available reports:\n"; + Catch::cout() << "Available reporters:\n"; IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; std::size_t maxNameLen = 0; @@ -4752,13 +4890,13 @@ namespace Catch { .setInitialIndent( 0 ) .setIndent( 7+maxNameLen ) .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); - std::cout << " " + Catch::cout() << " " << it->first << ":" << std::string( maxNameLen - it->first.size() + 2, ' ' ) << wrapper << "\n"; } - std::cout << std::endl; + Catch::cout() << std::endl; return factories.size(); } @@ -4915,6 +5053,81 @@ using SectionTracking::TestCaseTracker; } // namespace Catch +// #included from: catch_fatal_condition.hpp +#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED + +namespace Catch { + + // Report the error condition then exit the process + inline void fatal( std::string const& message, int exitCode ) { + IContext& context = Catch::getCurrentContext(); + IResultCapture* resultCapture = context.getResultCapture(); + resultCapture->handleFatalErrorCondition( message ); + + if( Catch::alwaysTrue() ) // avoids "no return" warnings + exit( exitCode ); + } + +} // namespace Catch + +#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// + +namespace Catch { + + struct FatalConditionHandler { + void reset() {} + }; + +} // namespace Catch + +#else // Not Windows - assumed to be POSIX compatible ////////////////////////// + +#include + +namespace Catch { + + struct SignalDefs { int id; const char* name; }; + extern SignalDefs signalDefs[]; + SignalDefs signalDefs[] = { + { SIGINT, "SIGINT - Terminal interrupt signal" }, + { SIGILL, "SIGILL - Illegal instruction signal" }, + { SIGFPE, "SIGFPE - Floating point error signal" }, + { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, + { SIGTERM, "SIGTERM - Termination request signal" }, + { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } + }; + + struct FatalConditionHandler { + + static void handleSignal( int sig ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + if( sig == signalDefs[i].id ) + fatal( signalDefs[i].name, -sig ); + fatal( "", -sig ); + } + + FatalConditionHandler() : m_isSet( true ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, handleSignal ); + } + ~FatalConditionHandler() { + reset(); + } + void reset() { + if( m_isSet ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, SIG_DFL ); + m_isSet = false; + } + } + + bool m_isSet; + }; + +} // namespace Catch + +#endif // not Windows + #include #include @@ -5102,6 +5315,37 @@ namespace Catch { return &m_lastResult; } + virtual void handleFatalErrorCondition( std::string const& message ) { + ResultBuilder resultBuilder = makeUnexpectedResultBuilder(); + resultBuilder.setResultType( ResultWas::FatalErrorCondition ); + resultBuilder << message; + resultBuilder.captureExpression(); + + handleUnfinishedSections(); + + // Recreate section for test case (as we will lose the one that was in scope) + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + + Counts assertions; + assertions.failed = 1; + SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false ); + m_reporter->sectionEnded( testCaseSectionStats ); + + TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo(); + + Totals deltaTotals; + deltaTotals.testCases.failed = 1; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + "", + "", + false ) ); + m_totals.testCases.failed++; + testGroupEnded( "", m_totals, 1, 1 ); + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); + } + public: // !TBD We need to do this another way! bool aborting() const { @@ -5123,12 +5367,12 @@ namespace Catch { Timer timer; timer.start(); if( m_reporter->getPreferences().shouldRedirectStdOut ) { - StreamRedirect coutRedir( std::cout, redirectedCout ); - StreamRedirect cerrRedir( std::cerr, redirectedCerr ); - m_activeTestCase->invoke(); + StreamRedirect coutRedir( Catch::cout(), redirectedCout ); + StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr ); + invokeActiveTestCase(); } else { - m_activeTestCase->invoke(); + invokeActiveTestCase(); } duration = timer.getElapsedSeconds(); } @@ -5136,20 +5380,9 @@ namespace Catch { // This just means the test was aborted due to failure } catch(...) { - ResultBuilder exResult( m_lastAssertionInfo.macroName.c_str(), - m_lastAssertionInfo.lineInfo, - m_lastAssertionInfo.capturedExpression.c_str(), - m_lastAssertionInfo.resultDisposition ); - exResult.useActiveException(); + makeUnexpectedResultBuilder().useActiveException(); } - // If sections ended prematurely due to an exception we stored their - // infos here so we can tear them down outside the unwind process. - for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), - itEnd = m_unfinishedSections.rend(); - it != itEnd; - ++it ) - sectionEnded( it->info, it->prevAssertions, it->durationInSeconds ); - m_unfinishedSections.clear(); + handleUnfinishedSections(); m_messages.clear(); Counts assertions = m_totals.assertions - prevAssertions; @@ -5165,7 +5398,32 @@ namespace Catch { m_reporter->sectionEnded( testCaseSectionStats ); } + void invokeActiveTestCase() { + FatalConditionHandler fatalConditionHandler; // Handle signals + m_activeTestCase->invoke(); + fatalConditionHandler.reset(); + } + private: + + ResultBuilder makeUnexpectedResultBuilder() const { + return ResultBuilder( m_lastAssertionInfo.macroName.c_str(), + m_lastAssertionInfo.lineInfo, + m_lastAssertionInfo.capturedExpression.c_str(), + m_lastAssertionInfo.resultDisposition ); + } + + void handleUnfinishedSections() { + // If sections ended prematurely due to an exception we stored their + // infos here so we can tear them down outside the unwind process. + for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), + itEnd = m_unfinishedSections.rend(); + it != itEnd; + ++it ) + sectionEnded( it->info, it->prevAssertions, it->durationInSeconds ); + m_unfinishedSections.clear(); + } + struct UnfinishedSections { UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds ) : info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) @@ -5253,7 +5511,7 @@ namespace Catch { Totals totals; - context.testGroupStarting( "", 1, 1 ); // deprecated? + context.testGroupStarting( "all tests", 1, 1 ); // deprecated? TestSpec testSpec = m_config->testSpec(); if( !testSpec.hasFilters() ) @@ -5276,7 +5534,15 @@ namespace Catch { m_testsAlreadyRun.insert( *it ); } } - context.testGroupEnded( "", totals, 1, 1 ); + std::vector skippedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, skippedTestCases, true ); + + for( std::vector::const_iterator it = skippedTestCases.begin(), itEnd = skippedTestCases.end(); + it != itEnd; + ++it ) + m_reporter->skipTest( *it ); + + context.testGroupEnded( "all tests", totals, 1, 1 ); return totals; } @@ -5313,7 +5579,7 @@ namespace Catch { std::set m_testsAlreadyRun; }; - class Session { + class Session : NonCopyable { static bool alreadyInstantiated; public: @@ -5324,7 +5590,7 @@ namespace Catch { : m_cli( makeCommandLineParser() ) { if( alreadyInstantiated ) { std::string msg = "Only one instance of Catch::Session can ever be used"; - std::cerr << msg << std::endl; + Catch::cerr() << msg << std::endl; throw std::logic_error( msg ); } alreadyInstantiated = true; @@ -5334,15 +5600,15 @@ namespace Catch { } void showHelp( std::string const& processName ) { - std::cout << "\nCatch v" << libraryVersion.majorVersion << "." + Catch::cout() << "\nCatch v" << libraryVersion.majorVersion << "." << libraryVersion.minorVersion << " build " << libraryVersion.buildNumber; if( libraryVersion.branchName != std::string( "master" ) ) - std::cout << " (" << libraryVersion.branchName << " branch)"; - std::cout << "\n"; + Catch::cout() << " (" << libraryVersion.branchName << " branch)"; + Catch::cout() << "\n"; - m_cli.usage( std::cout, processName ); - std::cout << "For more detail usage please see the project docs\n" << std::endl; + m_cli.usage( Catch::cout(), processName ); + Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; } int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { @@ -5356,11 +5622,11 @@ namespace Catch { catch( std::exception& ex ) { { Colour colourGuard( Colour::Red ); - std::cerr << "\nError(s) in input:\n" + Catch::cerr() << "\nError(s) in input:\n" << Text( ex.what(), TextAttributes().setIndent(2) ) << "\n\n"; } - m_cli.usage( std::cout, m_configData.processName ); + m_cli.usage( Catch::cout(), m_configData.processName ); return (std::numeric_limits::max)(); } return 0; @@ -5386,6 +5652,9 @@ namespace Catch { try { config(); // Force config to be constructed + + std::srand( m_configData.rngSeed ); + Runner runner( m_config ); // Handle list request @@ -5395,7 +5664,7 @@ namespace Catch { return static_cast( runner.runTests().assertions.failed ); } catch( std::exception& ex ) { - std::cerr << ex.what() << std::endl; + Catch::cerr() << ex.what() << std::endl; return (std::numeric_limits::max)(); } } @@ -5436,10 +5705,18 @@ namespace Catch { #include #include #include +#include namespace Catch { class TestRegistry : public ITestCaseRegistry { + struct LexSort { + bool operator() (TestCase i,TestCase j) const { return (i& matchingTestCases ) const { + virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const { + for( std::vector::const_iterator it = m_functionsInOrder.begin(), itEnd = m_functionsInOrder.end(); it != itEnd; ++it ) { - if( testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() ) ) + bool includeTest = testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() ); + if( includeTest != negated ) matchingTestCases.push_back( *it ); } + sortTests( config, matchingTestCases ); } private: + static void sortTests( IConfig const& config, std::vector& matchingTestCases ) { + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( matchingTestCases.begin(), matchingTestCases.end(), LexSort() ); + break; + case RunTests::InRandomOrder: + { + RandomNumberGenerator rng; + std::random_shuffle( matchingTestCases.begin(), matchingTestCases.end(), rng ); + } + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + } std::set m_functions; std::vector m_functionsInOrder; std::vector m_nonHiddenFunctions; @@ -5613,7 +5910,7 @@ namespace Catch { throw; } @catch (NSException *exception) { - return toString( [exception description] ); + return Catch::toString( [exception description] ); } #else throw; @@ -5760,6 +6057,7 @@ namespace Catch { #include #include +#include namespace Catch { @@ -5823,6 +6121,15 @@ namespace Catch { isOwned = false; } } + +#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement this functions + std::ostream& cout() { + return std::cout; + } + std::ostream& cerr() { + return std::cerr; + } +#endif } namespace Catch { @@ -5908,8 +6215,8 @@ namespace Catch { } Stream createStream( std::string const& streamName ) { - if( streamName == "stdout" ) return Stream( std::cout.rdbuf(), false ); - if( streamName == "stderr" ) return Stream( std::cerr.rdbuf(), false ); + if( streamName == "stdout" ) return Stream( Catch::cout().rdbuf(), false ); + if( streamName == "stderr" ) return Stream( Catch::cerr().rdbuf(), false ); if( streamName == "debug" ) return Stream( new StreamBufImpl, true ); throw std::domain_error( "Unknown stream: " + streamName ); @@ -5924,14 +6231,35 @@ namespace Catch { // #included from: catch_console_colour_impl.hpp #define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED -namespace Catch { namespace Detail { - struct IColourImpl { - virtual ~IColourImpl() {} - virtual void use( Colour::Code _colourCode ) = 0; - }; -}} +namespace Catch { + namespace { -#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// + struct IColourImpl { + virtual ~IColourImpl() {} + virtual void use( Colour::Code _colourCode ) = 0; + }; + + struct NoColourImpl : IColourImpl { + void use( Colour::Code ) {} + + static IColourImpl* instance() { + static NoColourImpl s_instance; + return &s_instance; + } + }; + + } // anon namespace +} // namespace Catch + +#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) +# ifdef CATCH_PLATFORM_WINDOWS +# define CATCH_CONFIG_COLOUR_WINDOWS +# else +# define CATCH_CONFIG_COLOUR_ANSI +# endif +#endif + +#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// #ifndef NOMINMAX #define NOMINMAX @@ -5946,7 +6274,7 @@ namespace Catch { namespace Detail { namespace Catch { namespace { - class Win32ColourImpl : public Detail::IColourImpl { + class Win32ColourImpl : public IColourImpl { public: Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) { @@ -5983,11 +6311,7 @@ namespace { WORD originalAttributes; }; - inline bool shouldUseColourForPlatform() { - return true; - } - - static Detail::IColourImpl* platformColourInstance() { + IColourImpl* platformColourInstance() { static Win32ColourImpl s_instance; return &s_instance; } @@ -5995,7 +6319,7 @@ namespace { } // end anon namespace } // end namespace Catch -#else // Not Windows - assumed to be POSIX compatible ////////////////////////// +#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// #include @@ -6006,7 +6330,7 @@ namespace { // Thanks to Adam Strzelecki for original contribution // (http://github.com/nanoant) // https://github.com/philsquared/Catch/pull/131 - class PosixColourImpl : public Detail::IColourImpl { + class PosixColourImpl : public IColourImpl { public: virtual void use( Colour::Code _colourCode ) { switch( _colourCode ) { @@ -6027,53 +6351,47 @@ namespace { case Colour::Bright: throw std::logic_error( "not a colour" ); } } + static IColourImpl* instance() { + static PosixColourImpl s_instance; + return &s_instance; + } + private: void setColour( const char* _escapeCode ) { - std::cout << '\033' << _escapeCode; + Catch::cout() << '\033' << _escapeCode; } }; - inline bool shouldUseColourForPlatform() { - return isatty(STDOUT_FILENO); - } - - static Detail::IColourImpl* platformColourInstance() { - static PosixColourImpl s_instance; - return &s_instance; + IColourImpl* platformColourInstance() { + return isatty(STDOUT_FILENO) + ? PosixColourImpl::instance() + : NoColourImpl::instance(); } } // end anon namespace } // end namespace Catch -#endif // not Windows +#else // not Windows or ANSI /////////////////////////////////////////////// namespace Catch { - namespace { - struct NoColourImpl : Detail::IColourImpl { - void use( Colour::Code ) {} + static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } - static IColourImpl* instance() { - static NoColourImpl s_instance; - return &s_instance; - } - }; - static bool shouldUseColour() { - return shouldUseColourForPlatform() && !isDebuggerActive(); - } - } +} // end namespace Catch + +#endif // Windows/ ANSI/ None + +namespace Catch { Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast( _other ).m_moved = true; } Colour::~Colour(){ if( !m_moved ) use( None ); } - void Colour::use( Code _colourCode ) { - impl()->use( _colourCode ); - } - Detail::IColourImpl* Colour::impl() { - return shouldUseColour() - ? platformColourInstance() - : NoColourImpl::instance(); + void Colour::use( Code _colourCode ) { + static IColourImpl* impl = isDebuggerActive() + ? NoColourImpl::instance() + : platformColourInstance(); + impl->use( _colourCode ); } } // end namespace Catch @@ -6238,7 +6556,7 @@ namespace Catch { namespace Catch { inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { - if( tag == "." || + if( startsWith( tag, "." ) || tag == "hide" || tag == "!hide" ) return TestCaseInfo::IsHidden; @@ -6252,19 +6570,19 @@ namespace Catch { return TestCaseInfo::None; } inline bool isReservedTag( std::string const& tag ) { - return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] ); + return TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] ); } inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { if( isReservedTag( tag ) ) { { Colour colourGuard( Colour::Red ); - std::cerr + Catch::cerr() << "Tag name [" << tag << "] not allowed.\n" << "Tag names starting with non alpha-numeric characters are reserved\n"; } { Colour colourGuard( Colour::FileName ); - std::cerr << _lineInfo << std::endl; + Catch::cerr() << _lineInfo << std::endl; } exit(1); } @@ -6292,14 +6610,15 @@ namespace Catch { } else { if( c == ']' ) { - enforceNotReservedTag( tag, _lineInfo ); - - inTag = false; - if( tag == "hide" || tag == "." ) + TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); + if( prop == TestCaseInfo::IsHidden ) isHidden = true; - else - tags.insert( tag ); + else if( prop == TestCaseInfo::None ) + enforceNotReservedTag( tag, _lineInfo ); + + tags.insert( tag ); tag.clear(); + inTag = false; } else tag += c; @@ -6417,7 +6736,7 @@ namespace Catch { namespace Catch { // These numbers are maintained by a script - Version libraryVersion( 1, 0, 53, "master" ); + Version libraryVersion( 1, 1, 13, "develop" ); } // #included from: catch_message.hpp @@ -6501,6 +6820,7 @@ namespace Catch virtual void testCaseEnded( TestCaseStats const& testCaseStats ); virtual void testGroupEnded( TestGroupStats const& testGroupStats ); virtual void testRunEnded( TestRunStats const& testRunStats ); + virtual void skipTest( TestCaseInfo const& ); private: Ptr m_legacyReporter; @@ -6574,6 +6894,8 @@ namespace Catch void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { m_legacyReporter->EndTesting( testRunStats.totals ); } + void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { + } } // #included from: catch_timer.hpp @@ -6615,14 +6937,14 @@ namespace Catch { void Timer::start() { m_ticks = getCurrentTicks(); } - unsigned int Timer::getElapsedNanoseconds() const { + unsigned int Timer::getElapsedMicroseconds() const { return static_cast(getCurrentTicks() - m_ticks); } unsigned int Timer::getElapsedMilliseconds() const { - return static_cast((getCurrentTicks() - m_ticks)/1000); + return static_cast(getElapsedMicroseconds()/1000); } double Timer::getElapsedSeconds() const { - return (getCurrentTicks() - m_ticks)/1000000.0; + return getElapsedMicroseconds()/1000000.0; } } // namespace Catch @@ -6660,6 +6982,20 @@ namespace Catch { return start != std::string::npos ? str.substr( start, 1+end-start ) : ""; } + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { + bool replaced = false; + std::size_t i = str.find( replaceThis ); + while( i != std::string::npos ) { + replaced = true; + str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); + if( i < str.size()-withThis.size() ) + i = str.find( replaceThis, i+withThis.size() ); + else + i = std::string::npos; + } + return replaced; + } + pluralise::pluralise( std::size_t count, std::string const& label ) : m_count( count ), m_label( label ) @@ -6781,7 +7117,7 @@ namespace Catch { size = sizeof(info); if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0) != 0 ) { - std::cerr << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; + Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; return false; } @@ -6822,7 +7158,7 @@ namespace Catch { namespace Catch { void writeToDebugConsole( std::string const& text ) { // !TBD: Need a version for Mac/ XCode and other IDEs - std::cout << text; + Catch::cout() << text; } } #endif // Platform @@ -6834,6 +7170,8 @@ namespace Catch { namespace Detail { + std::string unprintableString = "{?}"; + namespace { struct Endianness { enum Arch { Big, Little }; @@ -6892,7 +7230,7 @@ std::string toString( std::wstring const& value ) { s.reserve( value.size() ); for(size_t i = 0; i < value.size(); ++i ) s += value[i] <= 0xff ? static_cast( value[i] ) : '?'; - return toString( s ); + return Catch::toString( s ); } std::string toString( const char* const value ) { @@ -6915,7 +7253,10 @@ std::string toString( wchar_t* const value ) std::string toString( int value ) { std::ostringstream oss; - oss << value; + if( value > 8192 ) + oss << "0x" << std::hex << value; + else + oss << value; return oss.str(); } @@ -6929,7 +7270,7 @@ std::string toString( unsigned long value ) { } std::string toString( unsigned int value ) { - return toString( static_cast( value ) ); + return Catch::toString( static_cast( value ) ); } template @@ -7195,7 +7536,7 @@ namespace Catch { } catch( std::exception& ex ) { Colour colourGuard( Colour::Red ); - std::cerr << ex.what() << std::endl; + Catch::cerr() << ex.what() << std::endl; exit(1); } } @@ -7208,6 +7549,8 @@ namespace Catch { // #included from: catch_reporter_bases.hpp #define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED +#include + namespace Catch { struct StreamingReporterBase : SharedImpl { @@ -7251,6 +7594,11 @@ namespace Catch { currentTestRunInfo.reset(); } + virtual void skipTest( TestCaseInfo const& ) { + // Don't do anything with this by default. + // It can optionally be overridden in the derived class. + } + Ptr m_config; std::ostream& stream; @@ -7380,6 +7728,8 @@ namespace Catch { } virtual void testRunEndedCumulative() = 0; + virtual void skipTest( TestCaseInfo const& ) {} + Ptr m_config; std::ostream& stream; std::vector m_assertions; @@ -7395,6 +7745,16 @@ namespace Catch { }; + template + char const* getLineOfChars() { + static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; + if( !*line ) { + memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); + line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; + } + return line; + } + } // end namespace Catch // #included from: ../internal/catch_reporter_registrars.hpp @@ -7464,7 +7824,6 @@ namespace Catch { #define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED #include -#include #include #include @@ -7507,7 +7866,7 @@ namespace Catch { XmlWriter() : m_tagIsOpen( false ), m_needsNewline( false ), - m_os( &std::cout ) + m_os( &Catch::cout() ) {} XmlWriter( std::ostream& os ) @@ -7677,81 +8036,90 @@ namespace Catch { } namespace Catch { - class XmlReporter : public SharedImpl { + class XmlReporter : public StreamingReporterBase { public: - XmlReporter( ReporterConfig const& config ) : m_config( config ), m_sectionDepth( 0 ) {} + XmlReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_sectionDepth( 0 ) + {} + + virtual ~XmlReporter(); static std::string getDescription() { return "Reports test results as an XML document"; } - virtual ~XmlReporter(); - - private: // IReporter - virtual bool shouldRedirectStdout() const { - return true; + public: // StreamingReporterBase + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = true; + return prefs; } - virtual void StartTesting() { - m_xml.setStream( m_config.stream() ); - m_xml.startElement( "Catch" ); - if( !m_config.fullConfig()->name().empty() ) - m_xml.writeAttribute( "name", m_config.fullConfig()->name() ); + virtual void noMatchingTestCases( std::string const& s ) { + StreamingReporterBase::noMatchingTestCases( s ); } - virtual void EndTesting( const Totals& totals ) { - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", totals.assertions.passed ) - .writeAttribute( "failures", totals.assertions.failed ) - .writeAttribute( "expectedFailures", totals.assertions.failedButOk ); - m_xml.endElement(); + virtual void testRunStarting( TestRunInfo const& testInfo ) { + StreamingReporterBase::testRunStarting( testInfo ); + m_xml.setStream( stream ); + m_xml.startElement( "Catch" ); + if( !m_config->name().empty() ) + m_xml.writeAttribute( "name", m_config->name() ); } - virtual void StartGroup( const std::string& groupName ) { + virtual void testGroupStarting( GroupInfo const& groupInfo ) { + StreamingReporterBase::testGroupStarting( groupInfo ); m_xml.startElement( "Group" ) - .writeAttribute( "name", groupName ); + .writeAttribute( "name", groupInfo.name ); } - virtual void EndGroup( const std::string&, const Totals& totals ) { - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", totals.assertions.passed ) - .writeAttribute( "failures", totals.assertions.failed ) - .writeAttribute( "expectedFailures", totals.assertions.failedButOk ); - m_xml.endElement(); + virtual void testCaseStarting( TestCaseInfo const& testInfo ) { + StreamingReporterBase::testCaseStarting(testInfo); + m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); + + if ( m_config->showDurations() == ShowDurations::Always ) + m_testCaseTimer.start(); } - virtual void StartSection( const std::string& sectionName, const std::string& description ) { + virtual void sectionStarting( SectionInfo const& sectionInfo ) { + StreamingReporterBase::sectionStarting( sectionInfo ); if( m_sectionDepth++ > 0 ) { m_xml.startElement( "Section" ) - .writeAttribute( "name", trim( sectionName ) ) - .writeAttribute( "description", description ); + .writeAttribute( "name", trim( sectionInfo.name ) ) + .writeAttribute( "description", sectionInfo.description ); } } - virtual void NoAssertionsInSection( const std::string& ) {} - virtual void NoAssertionsInTestCase( const std::string& ) {} - virtual void EndSection( const std::string& /*sectionName*/, const Counts& assertions ) { - if( --m_sectionDepth > 0 ) { - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", assertions.passed ) - .writeAttribute( "failures", assertions.failed ) - .writeAttribute( "expectedFailures", assertions.failedButOk ); - m_xml.endElement(); - } - } + virtual void assertionStarting( AssertionInfo const& ) { } - virtual void StartTestCase( const Catch::TestCaseInfo& testInfo ) { - m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); - m_currentTestSuccess = true; - } + virtual bool assertionEnded( AssertionStats const& assertionStats ) { + const AssertionResult& assertionResult = assertionStats.assertionResult; - virtual void Result( const Catch::AssertionResult& assertionResult ) { - if( !m_config.fullConfig()->includeSuccessfulResults() && assertionResult.getResultType() == ResultWas::Ok ) - return; + // Print any info messages in tags. + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + m_xml.scopedElement( "Info" ) + .writeText( it->message ); + } else if ( it->type == ResultWas::Warning ) { + m_xml.scopedElement( "Warning" ) + .writeText( it->message ); + } + } + } + + // Drop out if result was successful but we're not printing them. + if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) ) + return true; + // Print the expression if there is one. if( assertionResult.hasExpression() ) { m_xml.startElement( "Expression" ) .writeAttribute( "success", assertionResult.succeeded() ) + .writeAttribute( "type", assertionResult.getTestMacroName() ) .writeAttribute( "filename", assertionResult.getSourceInfo().file ) .writeAttribute( "line", assertionResult.getSourceInfo().line ); @@ -7759,58 +8127,96 @@ namespace Catch { .writeText( assertionResult.getExpression() ); m_xml.scopedElement( "Expanded" ) .writeText( assertionResult.getExpandedExpression() ); - m_currentTestSuccess &= assertionResult.succeeded(); } + // And... Print a result applicable to each result type. switch( assertionResult.getResultType() ) { case ResultWas::ThrewException: m_xml.scopedElement( "Exception" ) .writeAttribute( "filename", assertionResult.getSourceInfo().file ) .writeAttribute( "line", assertionResult.getSourceInfo().line ) .writeText( assertionResult.getMessage() ); - m_currentTestSuccess = false; + break; + case ResultWas::FatalErrorCondition: + m_xml.scopedElement( "Fatal Error Condition" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); break; case ResultWas::Info: m_xml.scopedElement( "Info" ) .writeText( assertionResult.getMessage() ); break; case ResultWas::Warning: - m_xml.scopedElement( "Warning" ) - .writeText( assertionResult.getMessage() ); + // Warning will already have been written break; case ResultWas::ExplicitFailure: m_xml.scopedElement( "Failure" ) .writeText( assertionResult.getMessage() ); - m_currentTestSuccess = false; break; - case ResultWas::Unknown: - case ResultWas::Ok: - case ResultWas::FailureBit: - case ResultWas::ExpressionFailed: - case ResultWas::Exception: - case ResultWas::DidntThrowException: + default: break; } + if( assertionResult.hasExpression() ) m_xml.endElement(); + + return true; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) { + StreamingReporterBase::sectionEnded( sectionStats ); + if( --m_sectionDepth > 0 ) { + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); + e.writeAttribute( "successes", sectionStats.assertions.passed ); + e.writeAttribute( "failures", sectionStats.assertions.failed ); + e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); + + m_xml.endElement(); + } + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + StreamingReporterBase::testCaseEnded( testCaseStats ); + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); + e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); + + m_xml.endElement(); } - virtual void Aborted() { - // !TBD + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + StreamingReporterBase::testGroupEnded( testGroupStats ); + // TODO: Check testGroupStats.aborting and act accordingly. + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) + .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); + m_xml.endElement(); } - virtual void EndTestCase( const Catch::TestCaseInfo&, const Totals&, const std::string&, const std::string& ) { - m_xml.scopedElement( "OverallResult" ).writeAttribute( "success", m_currentTestSuccess ); + virtual void testRunEnded( TestRunStats const& testRunStats ) { + StreamingReporterBase::testRunEnded( testRunStats ); + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testRunStats.totals.assertions.passed ) + .writeAttribute( "failures", testRunStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); m_xml.endElement(); } private: - ReporterConfig m_config; - bool m_currentTestSuccess; + Timer m_testCaseTimer; XmlWriter m_xml; int m_sectionDepth; }; + INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) + } // end namespace Catch // #included from: ../reporters/catch_reporter_junit.hpp @@ -7937,7 +8343,7 @@ namespace Catch { xml.writeAttribute( "classname", className ); xml.writeAttribute( "name", name ); } - xml.writeAttribute( "time", toString( sectionNode.stats.durationInSeconds ) ); + xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) ); writeAssertions( sectionNode ); @@ -7970,6 +8376,7 @@ namespace Catch { std::string elementName; switch( result.getResultType() ) { case ResultWas::ThrewException: + case ResultWas::FatalErrorCondition: elementName = "error"; break; case ResultWas::ExplicitFailure: @@ -8028,8 +8435,6 @@ namespace Catch { // #included from: ../reporters/catch_reporter_console.hpp #define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED -#include - namespace Catch { struct ConsoleReporter : StreamingReporterBase { @@ -8164,6 +8569,11 @@ namespace Catch { passOrFail = "FAILED"; messageLabel = "due to unexpected exception with message"; break; + case ResultWas::FatalErrorCondition: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to a fatal error condition"; + break; case ResultWas::DidntThrowException: colour = Colour::Error; passOrFail = "FAILED"; @@ -8281,6 +8691,9 @@ namespace Catch { stream << " host application.\n" << "Run with -? for options\n\n"; + if( m_config->rngSeed() != 0 ) + stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; + currentTestRunInfo.used = true; } void lazyPrintGroupInfo() { @@ -8452,15 +8865,6 @@ namespace Catch { void printSummaryDivider() { stream << getLineOfChars<'-'>() << "\n"; } - template - static char const* getLineOfChars() { - static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; - if( !*line ) { - memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); - line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; - } - return line; - } private: bool m_headerPrinted; @@ -8569,6 +8973,13 @@ namespace Catch { printExpressionWas(); printRemainingMessages(); break; + case ResultWas::FatalErrorCondition: + printResultType( Colour::Error, failedString() ); + printIssue( "fatal error condition with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; case ResultWas::DidntThrowException: printResultType( Colour::Error, failedString() ); printIssue( "expected exception, got none" ); @@ -8798,8 +9209,6 @@ namespace Catch { Matchers::Impl::StdString::EndsWith::~EndsWith() {} void Config::dummy() {} - - INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( "xml", XmlReporter ) } #ifdef __clang__ From 16b9f350447dc0c75d096882de07008f4a990794 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 19 Jan 2015 20:22:01 -0500 Subject: [PATCH 0763/1866] adds basic repeat test --- catchtest/test_repeat.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 catchtest/test_repeat.cpp diff --git a/catchtest/test_repeat.cpp b/catchtest/test_repeat.cpp new file mode 100644 index 00000000..61977e92 --- /dev/null +++ b/catchtest/test_repeat.cpp @@ -0,0 +1,25 @@ +#include + +#include "helpers.hpp" + +#include +#include +#include + +#include "catch.hpp" + +using iter::repeat; + +TEST_CASE("repeat: one argument keeps giving value back", "[repeat]") { + auto r = repeat('a'); + auto it = std::begin(r); + REQUIRE( *it == 'a' ); + ++it; + REQUIRE( *it == 'a' ); + ++it; + REQUIRE( *it == 'a' ); + ++it; + REQUIRE( *it == 'a' ); + ++it; + REQUIRE( *it == 'a' ); +} From eabe0dcae6864052e69b42ecc69c211f7dfdb05e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 19 Jan 2015 20:26:34 -0500 Subject: [PATCH 0764/1866] repeat iterator is input iterator --- repeat.hpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/repeat.hpp b/repeat.hpp index 9753675d..a0b96cf5 100644 --- a/repeat.hpp +++ b/repeat.hpp @@ -1,5 +1,5 @@ -#ifndef REPEAT_HPP__ -#define REPEAT_HPP__ +#ifndef ITER_REPEAT_HPP_ +#define ITER_REPEAT_HPP_ #include #include @@ -28,7 +28,7 @@ namespace iter { { } public: - class Iterator { + class Iterator : public std::iterator { private: T& elem; int count; @@ -49,11 +49,21 @@ namespace iter { return *this; } + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + bool operator!=(const Iterator& other) const { return this->count != other.count || &this->elem != &other.elem; } + bool operator==(const Iterator& other) const { + return !(*this != other); + } + T& operator*() { return this->elem; } @@ -76,4 +86,4 @@ namespace iter { } -#endif //REPEAT_HPP__ +#endif From 79f250a1b69e27ce55176174dd461cb5ca58679b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 19 Jan 2015 20:31:24 -0500 Subject: [PATCH 0765/1866] makes repeat iterators assignable replaces reference with pointer --- repeat.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/repeat.hpp b/repeat.hpp index a0b96cf5..73e0ac27 100644 --- a/repeat.hpp +++ b/repeat.hpp @@ -30,10 +30,10 @@ namespace iter { class Iterator : public std::iterator { private: - T& elem; + T* elem; int count; public: - Iterator(T& e, int c) + Iterator(T* e, int c) : elem{e}, count{c} { } @@ -57,7 +57,7 @@ namespace iter { bool operator!=(const Iterator& other) const { return this->count != other.count || - &this->elem != &other.elem; + this->elem != other.elem; } bool operator==(const Iterator& other) const { @@ -65,16 +65,16 @@ namespace iter { } T& operator*() { - return this->elem; + return *this->elem; } }; Iterator begin() { - return {this->elem, this->count}; + return {&this->elem, this->count}; } Iterator end() { - return {this->elem, 0}; + return {&this->elem, 0}; } }; From 628a67259b3edcd2a789f1bb2a55ea13bb904c18 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 19 Jan 2015 20:32:14 -0500 Subject: [PATCH 0766/1866] tests repeat with count --- catchtest/test_repeat.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/catchtest/test_repeat.cpp b/catchtest/test_repeat.cpp index 61977e92..7d5fc098 100644 --- a/catchtest/test_repeat.cpp +++ b/catchtest/test_repeat.cpp @@ -23,3 +23,9 @@ TEST_CASE("repeat: one argument keeps giving value back", "[repeat]") { ++it; REQUIRE( *it == 'a' ); } + +TEST_CASE("repeat: two argument repeats a number of times", "[repeat]") { + auto r = repeat('a', 3); + std::string s(std::begin(r), std::end(r)); +} + From 5cdddbaf343fbef7bb461ba456e7903b471d1c57 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 19 Jan 2015 20:32:23 -0500 Subject: [PATCH 0767/1866] builds repeat test --- catchtest/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index ce88d2a3..62765a99 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -33,6 +33,7 @@ progs = Split( permutations powerset product + repeat ''' ) From 1bd10ca3bfb018b4453c8dc4f37fffa41986569c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 19 Jan 2015 20:37:08 -0500 Subject: [PATCH 0768/1866] actually tests repeat with count --- catchtest/test_repeat.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/catchtest/test_repeat.cpp b/catchtest/test_repeat.cpp index 7d5fc098..a8a4c1e9 100644 --- a/catchtest/test_repeat.cpp +++ b/catchtest/test_repeat.cpp @@ -27,5 +27,5 @@ TEST_CASE("repeat: one argument keeps giving value back", "[repeat]") { TEST_CASE("repeat: two argument repeats a number of times", "[repeat]") { auto r = repeat('a', 3); std::string s(std::begin(r), std::end(r)); + REQUIRE( s == "aaa" ); } - From 7804aa319d7cd97fd968a908cd4df58b430eafd8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 19 Jan 2015 20:38:21 -0500 Subject: [PATCH 0769/1866] tests repeat with 0 count --- catchtest/test_repeat.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/catchtest/test_repeat.cpp b/catchtest/test_repeat.cpp index a8a4c1e9..f93bc18b 100644 --- a/catchtest/test_repeat.cpp +++ b/catchtest/test_repeat.cpp @@ -29,3 +29,8 @@ TEST_CASE("repeat: two argument repeats a number of times", "[repeat]") { std::string s(std::begin(r), std::end(r)); REQUIRE( s == "aaa" ); } + +TEST_CASE("repeat: 0 count gives empty sequence", "[repeat]") { + auto r = repeat('a', 0); + REQUIRE( std::begin(r) == std::end(r) ); +} From 04b97b5103e62ae5ed41eebb6e0d0dc420053a00 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 19 Jan 2015 22:14:16 -0500 Subject: [PATCH 0770/1866] Repeat strips reference from pointer type --- repeat.hpp | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/repeat.hpp b/repeat.hpp index 73e0ac27..749972d0 100644 --- a/repeat.hpp +++ b/repeat.hpp @@ -2,6 +2,7 @@ #define ITER_REPEAT_HPP_ #include +#include #include namespace iter { @@ -13,12 +14,17 @@ namespace iter { class Repeater; template - Repeater repeat(T&&, int count =INFINITE_REPEAT); + Repeater repeat(T&&); + + template + Repeater repeat(T&&, int); template class Repeater { + friend Repeater repeat(T&&); friend Repeater repeat(T&&, int); private: + using TPlain = typename std::remove_reference::type; T elem; int count; @@ -28,12 +34,14 @@ namespace iter { { } public: - class Iterator : public std::iterator { + class Iterator + : public std::iterator + { private: - T* elem; + TPlain* elem; int count; public: - Iterator(T* e, int c) + Iterator(TPlain* e, int c) : elem{e}, count{c} { } @@ -80,10 +88,15 @@ namespace iter { }; template - Repeater repeat(T&& e, int count) { - return {std::forward(e), count}; + Repeater repeat(T&& e) { + return {std::forward(e), INFINITE_REPEAT}; } + template + Repeater repeat(T&& e, int count) { + // if count is negative, pass 0 instead + return {std::forward(e), count < 0 ? 0 : count}; + } } #endif From f130b82db3e54b32f83f8ddcf301f47058a49480 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 19 Jan 2015 22:14:46 -0500 Subject: [PATCH 0771/1866] tests that repeat doesn't copy element --- catchtest/test_repeat.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/catchtest/test_repeat.cpp b/catchtest/test_repeat.cpp index f93bc18b..0f159d29 100644 --- a/catchtest/test_repeat.cpp +++ b/catchtest/test_repeat.cpp @@ -34,3 +34,18 @@ TEST_CASE("repeat: 0 count gives empty sequence", "[repeat]") { auto r = repeat('a', 0); REQUIRE( std::begin(r) == std::end(r) ); } + +TEST_CASE("repeat: negative count gives empty sequence", "[repeat]") { + auto r = repeat('a', -2); + REQUIRE( std::begin(r) == std::end(r) ); + auto r2 = repeat('a', -1); + REQUIRE( std::begin(r2) == std::end(r2) ); +} + +TEST_CASE("repeat: doesn't duplicate item", "[repeat]") { + itertest::SolidInt si{2}; + auto r = repeat(si); + auto it = std::begin(r); + (void)*it; +} + From 4f2ace1890adb9e1ec613f19dee5a74142e5bc92 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 19 Jan 2015 22:16:12 -0500 Subject: [PATCH 0772/1866] simplifies repeat iter == --- repeat.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/repeat.hpp b/repeat.hpp index 749972d0..03ecadce 100644 --- a/repeat.hpp +++ b/repeat.hpp @@ -64,12 +64,11 @@ namespace iter { } bool operator!=(const Iterator& other) const { - return this->count != other.count || - this->elem != other.elem; + return !(*this == other); } bool operator==(const Iterator& other) const { - return !(*this != other); + return this->count == other.count; } T& operator*() { From 24709fe0e8659081082ada9c5dfe55841e0eb1f2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 20 Jan 2015 14:27:44 -0500 Subject: [PATCH 0773/1866] reversed iter inherits from std::iterator --- reversed.hpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/reversed.hpp b/reversed.hpp index dd7a0cc2..483a9ebb 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -28,7 +28,10 @@ namespace iter { public: Reverser(const Reverser&) = default; - class Iterator { + class Iterator : public std::iterator< + std::input_iterator_tag, + iterator_traits_deref> + { private: reverse_iterator_type sub_iter; public: @@ -60,7 +63,6 @@ namespace iter { }; - // Helper function to instantiate a Reverser template Reverser reversed(Container&& container) { return {std::forward(container)}; @@ -76,8 +78,6 @@ namespace iter { class Reverser { private: T *array; - // The reversed function is the only thing allowed to create a - // Reverser friend Reverser reversed(T (&)[N]); // Value constructor for use only in the reversed function @@ -89,7 +89,8 @@ namespace iter { public: Reverser(const Reverser&) = default; - class Iterator { + class Iterator : public std::iterator + { private: T *sub_iter; public: From 3d9012f5460cb3fd5e6723e7ee22b998b01c31f3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 20 Jan 2015 14:29:04 -0500 Subject: [PATCH 0774/1866] adds reversed iter == and postfix ++ --- reversed.hpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/reversed.hpp b/reversed.hpp index 483a9ebb..7563b898 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -48,9 +48,19 @@ namespace 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() { @@ -107,9 +117,19 @@ namespace 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() { From aa4b3738a18c51c36fe29c25af8e13aa85083a01 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 20 Jan 2015 14:29:26 -0500 Subject: [PATCH 0775/1866] tests simple reversed --- catchtest/test_reversed.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 catchtest/test_reversed.cpp diff --git a/catchtest/test_reversed.cpp b/catchtest/test_reversed.cpp new file mode 100644 index 00000000..9388592a --- /dev/null +++ b/catchtest/test_reversed.cpp @@ -0,0 +1,20 @@ +#include + +#include +#include + +#include "helpers.hpp" +#include "catch.hpp" + +using iter::reversed; +using Vec = const std::vector; + +TEST_CASE("Reversing a vector", "[reversed]") { + Vec ns = {10, 20, 30, 40}; + auto r = reversed(ns); + + Vec v(std::begin(r), std::end(r)); + Vec vc = {40, 30, 20, 10}; + + REQUIRE( v == vc ); +} From 4c9bd101d9b5e0149f55ce91649e6c810ed75c42 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 20 Jan 2015 14:29:44 -0500 Subject: [PATCH 0776/1866] builds reversed test --- catchtest/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index 62765a99..6192441a 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -34,6 +34,7 @@ progs = Split( powerset product repeat + reversed ''' ) From f01bb1b69062d79923c636386e7b405bed79fb85 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 20 Jan 2015 14:33:13 -0500 Subject: [PATCH 0777/1866] tests reversed with array --- catchtest/test_reversed.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/catchtest/test_reversed.cpp b/catchtest/test_reversed.cpp index 9388592a..2c16591f 100644 --- a/catchtest/test_reversed.cpp +++ b/catchtest/test_reversed.cpp @@ -9,7 +9,7 @@ using iter::reversed; using Vec = const std::vector; -TEST_CASE("Reversing a vector", "[reversed]") { +TEST_CASE("reversed: can reverse a vector", "[reversed]") { Vec ns = {10, 20, 30, 40}; auto r = reversed(ns); @@ -18,3 +18,13 @@ TEST_CASE("Reversing a vector", "[reversed]") { REQUIRE( v == vc ); } + +TEST_CASE("reversed: can reverse an array", "[reversed]") { + int ns[] = {10, 20, 30, 40}; + auto r = reversed(ns); + + Vec v(std::begin(r), std::end(r)); + Vec vc = {40, 30, 20, 10}; + + REQUIRE( v == vc ); +} From c191ef881658da60e2731daa516e66e646a83170 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 20 Jan 2015 14:34:59 -0500 Subject: [PATCH 0778/1866] tests reversed with empy vector --- catchtest/test_reversed.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/catchtest/test_reversed.cpp b/catchtest/test_reversed.cpp index 2c16591f..669f2bb2 100644 --- a/catchtest/test_reversed.cpp +++ b/catchtest/test_reversed.cpp @@ -28,3 +28,10 @@ TEST_CASE("reversed: can reverse an array", "[reversed]") { REQUIRE( v == vc ); } + +TEST_CASE("reversed: empty when iterable is empty", "[reversed]") { + Vec emp{}; + auto r = reversed(emp); + REQUIRE( std::begin(r) == std::end(r) ); +} + From 34eb516bb4f4aea8c07e25dad27240fc9b0471d4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 20 Jan 2015 14:44:04 -0500 Subject: [PATCH 0779/1866] tests that reversed binds and moves correctly --- catchtest/test_reversed.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/catchtest/test_reversed.cpp b/catchtest/test_reversed.cpp index 669f2bb2..5b9e0360 100644 --- a/catchtest/test_reversed.cpp +++ b/catchtest/test_reversed.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "helpers.hpp" #include "catch.hpp" @@ -35,3 +36,12 @@ TEST_CASE("reversed: empty when iterable is empty", "[reversed]") { REQUIRE( std::begin(r) == std::end(r) ); } +TEST_CASE("reversed: moves rvalues and binds to lvalues", "[reversed]") { + itertest::BasicIterable bi{1, 2}; + itertest::BasicIterable bi2{1, 2}; + reversed(bi); + REQUIRE_FALSE( bi.was_moved_from() ); + + reversed(std::move(bi2)); + REQUIRE( bi2.was_moved_from() ); +} From 72caaafff0d2754e3c9bf7d4d80b48befe2004e4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 20 Jan 2015 14:44:30 -0500 Subject: [PATCH 0780/1866] tests that reversed doesn't move or copy elements --- catchtest/test_reversed.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/catchtest/test_reversed.cpp b/catchtest/test_reversed.cpp index 5b9e0360..2fc2adc6 100644 --- a/catchtest/test_reversed.cpp +++ b/catchtest/test_reversed.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include @@ -45,3 +46,17 @@ TEST_CASE("reversed: moves rvalues and binds to lvalues", "[reversed]") { reversed(std::move(bi2)); REQUIRE( bi2.was_moved_from() ); } + +TEST_CASE("reversed: doesn't move or copy elements of array", "[reversed]") { + constexpr itertest::SolidInt arr[] = {{6}, {7}, {8}}; + for (auto&& i : reversed(arr)) { + (void)i; + } +} + +TEST_CASE("reversed: with iterable doesn't move or copy elems", "[reversed]") { + constexpr std::array arr{{{6}, {7}, {8}}}; + for (auto&& i : reversed(arr)) { + (void)i; + } +} From 0bf0d1a881143ccf9c6648beff3cdbd7c8ba3e0e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 21 Jan 2015 23:16:59 -0500 Subject: [PATCH 0781/1866] adds basic sliding_window test --- catchtest/test_sliding_window.cpp | 41 +++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 catchtest/test_sliding_window.cpp diff --git a/catchtest/test_sliding_window.cpp b/catchtest/test_sliding_window.cpp new file mode 100644 index 00000000..f3de1cd4 --- /dev/null +++ b/catchtest/test_sliding_window.cpp @@ -0,0 +1,41 @@ +#include + +#include +#include +#include +#include + +#include "helpers.hpp" +#include "catch.hpp" + +using iter::sliding_window; +using Vec = const std::vector; + +TEST_CASE("sliding_window: window of size 3", "[sliding_window]") { + Vec ns = { 10, 20, 30, 40, 50}; + auto sw = sliding_window(ns, 3); + auto it = std::begin(sw); + REQUIRE( it != std::end(sw) ); + { + Vec v(std::begin(*it), std::end(*it)); + Vec vc = {10, 20, 30}; + REQUIRE( v == vc ); + + } + ++it; + REQUIRE( it != std::end(sw) ); + { + Vec v(std::begin(*it), std::end(*it)); + Vec vc = {20, 30, 40}; + REQUIRE( v == vc ); + } + ++it; + REQUIRE( it != std::end(sw) ); + { + Vec v(std::begin(*it), std::end(*it)); + Vec vc = {30, 40, 50}; + REQUIRE( v == vc ); + } + ++it; + REQUIRE( !(it != std::end(sw)) ); +} From ec7cbc89900335f3c0bb6c39710d81f533d65f79 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 22 Jan 2015 00:10:20 -0500 Subject: [PATCH 0782/1866] adds test with oversides window --- catchtest/test_sliding_window.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/catchtest/test_sliding_window.cpp b/catchtest/test_sliding_window.cpp index f3de1cd4..2d67d2d8 100644 --- a/catchtest/test_sliding_window.cpp +++ b/catchtest/test_sliding_window.cpp @@ -39,3 +39,9 @@ TEST_CASE("sliding_window: window of size 3", "[sliding_window]") { ++it; REQUIRE( !(it != std::end(sw)) ); } + +TEST_CASE("sliding window: oversized window is empty", "[sliding_window]") { + Vec ns = {10, 20, 30}; + auto sw = sliding_window(ns, 5); + REQUIRE( !(std::begin(sw) != std::end(sw)) ); +} From 5a0798b3ff26c2234b25deca2e44d0abf2808957 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 23 Jan 2015 21:40:05 -0500 Subject: [PATCH 0783/1866] adds sliding_window test with max window size --- catchtest/test_sliding_window.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/catchtest/test_sliding_window.cpp b/catchtest/test_sliding_window.cpp index 2d67d2d8..75775985 100644 --- a/catchtest/test_sliding_window.cpp +++ b/catchtest/test_sliding_window.cpp @@ -45,3 +45,16 @@ TEST_CASE("sliding window: oversized window is empty", "[sliding_window]") { auto sw = sliding_window(ns, 5); REQUIRE( !(std::begin(sw) != std::end(sw)) ); } + +TEST_CASE("sliding window: window size == len(iterable)", "[sliding_window]") { + Vec ns = {10, 20, 30}; + auto sw = sliding_window(ns, 3); + auto it = std::begin(sw); + REQUIRE( it != std::end(sw) ); + + Vec v(std::begin(*it), std::end(*it)); + + REQUIRE( ns == v ); + ++it; + REQUIRE_FALSE( it != std::end(sw) ); +} From f7bbecaf2d66bda8b7a6158c07d01bf47e841816 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 23 Jan 2015 21:48:00 -0500 Subject: [PATCH 0784/1866] adds sliding_window test with window size of 1 --- catchtest/test_sliding_window.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/catchtest/test_sliding_window.cpp b/catchtest/test_sliding_window.cpp index 75775985..c8df3fb1 100644 --- a/catchtest/test_sliding_window.cpp +++ b/catchtest/test_sliding_window.cpp @@ -58,3 +58,22 @@ TEST_CASE("sliding window: window size == len(iterable)", "[sliding_window]") { ++it; REQUIRE_FALSE( it != std::end(sw) ); } + +TEST_CASE("sliding window: empty iterable is empty", "[sliding_window]") { + Vec ns{}; + auto sw = sliding_window(ns, 1); + REQUIRE_FALSE( std::begin(sw) != std::end(sw) ); +} + +TEST_CASE("sliding window: window size of 1", "[sliding_window]") { + Vec ns = {10, 20, 30}; + auto sw = sliding_window(ns, 1); + auto it = std::begin(sw); + REQUIRE( *std::begin(*it) == 10 ); + ++it; + REQUIRE( *std::begin(*it) == 20 ); + ++it; + REQUIRE( *std::begin(*it) == 30 ); + ++it; + REQUIRE_FALSE( it != std::end(sw) ); +} From 220fa3ade478d0976b66c08ba7762751bc5f6e44 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 23 Jan 2015 21:52:38 -0500 Subject: [PATCH 0785/1866] sliding window lazily consumes iterable --- sliding_window.hpp | 83 +++++++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 48 deletions(-) diff --git a/sliding_window.hpp b/sliding_window.hpp index 202191f1..1b9fb454 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -1,12 +1,9 @@ -#ifndef SLIDING_WINDOW_HPP_ -#define SLIDING_WINDOW_HPP_ +#ifndef ITER_SLIDING_WINDOW_HPP_ +#define ITER_SLIDING_WINDOW_HPP_ #include "iterbase.hpp" -#include -#include -#include -#include +#include #include #include @@ -23,8 +20,7 @@ namespace iter { template class SlidingWindow { - private: - Container container; + private: Container container; std::size_t window_size; friend SlidingWindow sliding_window( @@ -43,62 +39,53 @@ namespace iter { class Iterator { private: - // confusing, but, just makes the type of the vector - // returned by operator*() - using OpDerefElemType = - std::reference_wrapper< - typename std::remove_reference< - iterator_deref>::type>; - using DerefVec = std::vector; - - std::vector> section; - std::size_t section_size = 0; + // TODO move defs outside and subclass std::iterator + using OpDerefElemType = collection_item_type; + using DerefVec = std::deque; + + iterator_type sub_iter; + DerefVec window; public: - Iterator(Container& container, std::size_t s) - : section_size{s} + Iterator(const iterator_type& in_iter, + const iterator_type& in_end, + std::size_t window_sz) + : sub_iter(in_iter) { - auto iter = std::begin(container); - auto end = std::end(container); - for (std::size_t i = 0; - i < section_size && iter != end; - ++iter, ++i) { - section.push_back(iter); + std::size_t i{0}; + while (i < window_sz && this->sub_iter != in_end) { + this->window.push_back(*this->sub_iter); + ++i; + if (i != window_sz) ++this->sub_iter; } } - // for the end iter - Iterator(Container& container) - : section{std::end(container)}, - section_size{0} - { } - - Iterator& operator++() { - for (auto&& iter : this->section) { - ++iter; - } - return *this; + bool operator!=(const Iterator& other) const { + return this->sub_iter != other.sub_iter; } - bool operator!=(const Iterator& rhs) const { - return this->section.back() != rhs.section.back(); + DerefVec& operator*() { + return this->window; } - DerefVec operator*() { - DerefVec vec; - for (auto&& iter : this->section) { - vec.push_back(*iter); - } - return vec; + Iterator& operator++() { + ++this->sub_iter; + this->window.pop_front(); + this->window.push_back(*this->sub_iter); + return *this; } }; Iterator begin() { - return {container, window_size}; + return {std::begin(container), + std::end(container), + window_size}; } Iterator end() { - return {container}; + return {std::end(container), + std::end(container), + window_size}; } }; @@ -115,4 +102,4 @@ namespace iter { } } -#endif //SLIDING_WINDOW_HPP_ +#endif From ea81df388a0be484b673f6cbbbb00732689cdf2b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 23 Jan 2015 21:52:54 -0500 Subject: [PATCH 0786/1866] builds sliding_window catch test --- catchtest/SConstruct | 2 ++ 1 file changed, 2 insertions(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index 6192441a..aebe1c81 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -35,6 +35,8 @@ progs = Split( product repeat reversed + + sliding_window ''' ) From a6c67fff651749d933bfefd519fbf42e2332c168 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 23 Jan 2015 21:57:37 -0500 Subject: [PATCH 0787/1866] sliding_window iter inherits from std::iterator --- sliding_window.hpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sliding_window.hpp b/sliding_window.hpp index 1b9fb454..fec4052e 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -35,14 +35,13 @@ namespace iter { window_size{win_sz} { } + using DerefVec = std::deque>; public: - class Iterator { + class Iterator + : public std::iterator + { private: - // TODO move defs outside and subclass std::iterator - using OpDerefElemType = collection_item_type; - using DerefVec = std::deque; - iterator_type sub_iter; DerefVec window; From 67f4f417b9112a8fc04a70f977d1592e76fd6b44 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 23 Jan 2015 21:58:54 -0500 Subject: [PATCH 0788/1866] adds sliding_window iter postfix ++ --- sliding_window.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sliding_window.hpp b/sliding_window.hpp index fec4052e..63b573bf 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -73,6 +73,12 @@ namespace iter { this->window.push_back(*this->sub_iter); return *this; } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } }; Iterator begin() { From 29f69b5c731f701104344f3ce8418d424e1a8af8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 23 Jan 2015 22:00:00 -0500 Subject: [PATCH 0789/1866] adds sliding_window iter == --- sliding_window.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sliding_window.hpp b/sliding_window.hpp index 63b573bf..da22946d 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -63,6 +63,10 @@ namespace iter { return this->sub_iter != other.sub_iter; } + bool operator==(const Iterator& other) const { + return !(*this != other); + } + DerefVec& operator*() { return this->window; } From 83e28b68ba1082bed0b925c5d767c7c59bb00a9d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 23 Jan 2015 22:21:40 -0500 Subject: [PATCH 0790/1866] tests sliding_window with window size of 1 --- catchtest/test_sliding_window.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/catchtest/test_sliding_window.cpp b/catchtest/test_sliding_window.cpp index c8df3fb1..107e89c9 100644 --- a/catchtest/test_sliding_window.cpp +++ b/catchtest/test_sliding_window.cpp @@ -37,13 +37,13 @@ TEST_CASE("sliding_window: window of size 3", "[sliding_window]") { REQUIRE( v == vc ); } ++it; - REQUIRE( !(it != std::end(sw)) ); + REQUIRE( it == std::end(sw) ); } TEST_CASE("sliding window: oversized window is empty", "[sliding_window]") { Vec ns = {10, 20, 30}; auto sw = sliding_window(ns, 5); - REQUIRE( !(std::begin(sw) != std::end(sw)) ); + REQUIRE( std::begin(sw) == std::end(sw) ); } TEST_CASE("sliding window: window size == len(iterable)", "[sliding_window]") { @@ -56,13 +56,13 @@ TEST_CASE("sliding window: window size == len(iterable)", "[sliding_window]") { REQUIRE( ns == v ); ++it; - REQUIRE_FALSE( it != std::end(sw) ); + REQUIRE( it == std::end(sw) ); } TEST_CASE("sliding window: empty iterable is empty", "[sliding_window]") { Vec ns{}; auto sw = sliding_window(ns, 1); - REQUIRE_FALSE( std::begin(sw) != std::end(sw) ); + REQUIRE( std::begin(sw) == std::end(sw) ); } TEST_CASE("sliding window: window size of 1", "[sliding_window]") { @@ -75,5 +75,11 @@ TEST_CASE("sliding window: window size of 1", "[sliding_window]") { ++it; REQUIRE( *std::begin(*it) == 30 ); ++it; - REQUIRE_FALSE( it != std::end(sw) ); + REQUIRE( it == std::end(sw) ); +} + +TEST_CASE("sliding window: window size of 0", "[sliding_window]") { + Vec ns = {10, 20, 30}; + auto sw = sliding_window(ns, 0); + REQUIRE( std::begin(sw) == std::end(sw) ); } From 9eb90cb46db7d217dfcb28c0bdc895f9a54e6cfc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 23 Jan 2015 22:23:02 -0500 Subject: [PATCH 0791/1866] handles window size of 0 --- sliding_window.hpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/sliding_window.hpp b/sliding_window.hpp index da22946d..48d4ca1c 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -86,15 +86,18 @@ namespace iter { }; Iterator begin() { - return {std::begin(container), - std::end(container), - window_size}; + return { + (this->window_size != 0 ? + std::begin(this->container) + : std::end(this->container)), + std::end(this->container), + this->window_size}; } Iterator end() { - return {std::end(container), - std::end(container), - window_size}; + return {std::end(this->container), + std::end(this->container), + this->window_size}; } }; From 01cbbf9fcb647e45722d8f5090c19d65de2a7ac9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 24 Jan 2015 16:29:26 -0500 Subject: [PATCH 0792/1866] tests sliding window moves and binds correctly --- catchtest/test_sliding_window.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/catchtest/test_sliding_window.cpp b/catchtest/test_sliding_window.cpp index 107e89c9..95d40f1b 100644 --- a/catchtest/test_sliding_window.cpp +++ b/catchtest/test_sliding_window.cpp @@ -83,3 +83,12 @@ TEST_CASE("sliding window: window size of 0", "[sliding_window]") { auto sw = sliding_window(ns, 0); REQUIRE( std::begin(sw) == std::end(sw) ); } + +TEST_CASE("sliding window: moves rvalues and binds to lvalues", + "[sliding_window]") { + itertest::BasicIterable bi{1, 2}; + sliding_window(bi, 1); + REQUIRE_FALSE( bi.was_moved_from() ); + sliding_window(std::move(bi), 1); + REQUIRE( bi.was_moved_from() ); +} From 72a49e62da541c830411ece6323a30829639615e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 24 Jan 2015 16:31:59 -0500 Subject: [PATCH 0793/1866] tests sliding window doesn't copy elements --- catchtest/test_sliding_window.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/catchtest/test_sliding_window.cpp b/catchtest/test_sliding_window.cpp index 95d40f1b..3bcd0878 100644 --- a/catchtest/test_sliding_window.cpp +++ b/catchtest/test_sliding_window.cpp @@ -92,3 +92,10 @@ TEST_CASE("sliding window: moves rvalues and binds to lvalues", sliding_window(std::move(bi), 1); REQUIRE( bi.was_moved_from() ); } + +TEST_CASE("sliding window: doesn't copy elements", "[sliding_window]") { + constexpr std::array arr{{{6}, {7}, {8}}}; + for (auto&& i : sliding_window(arr, 1)) { + (void)*std::begin(i); + } +} From 733bfa598c4bc80b79b8d7a1f1418bf1d7a95a5a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 24 Jan 2015 16:55:26 -0500 Subject: [PATCH 0794/1866] basic takewhile test --- catchtest/test_takewhile.cpp | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 catchtest/test_takewhile.cpp diff --git a/catchtest/test_takewhile.cpp b/catchtest/test_takewhile.cpp new file mode 100644 index 00000000..9b92b9ab --- /dev/null +++ b/catchtest/test_takewhile.cpp @@ -0,0 +1,35 @@ +#include + +#include +#include +#include +#include + +#include "helpers.hpp" +#include "catch.hpp" + +using iter::takewhile; +using Vec = const std::vector; + + +namespace { + bool under_ten(int i) { + return i < 10; + } + + struct UnderTen { + bool operator()(int i) { + return i < 10; + } + }; +} + +TEST_CASE("takewhile: works with lambda, callable, and function pointer", + "[takewhile]") { + Vec ns = {1, 3, 5, 20, 2, 4, 6, 8}; + SECTION("function pointer") { + auto tw = takewhile(under_ten, ns); + Vec v(std::begin(tw), std::end(tw)); + + } +} From 5356ce0499adb10d7447185498e22212be29d618 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 24 Jan 2015 16:55:37 -0500 Subject: [PATCH 0795/1866] takewhile iter inherits from std iterator --- takewhile.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/takewhile.hpp b/takewhile.hpp index 528f6fb0..5447f791 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -1,5 +1,5 @@ -#ifndef TAKEWHILE__H__ -#define TAKEWHILE__H__ +#ifndef ITER_TAKEWHILE_H_ +#define ITER_TAKEWHILE_H_ #include "iterbase.hpp" @@ -39,13 +39,13 @@ namespace iter { filter_func(filter_func) { } - TakeWhile () = delete; - TakeWhile& operator=(const TakeWhile&) = delete; public: - TakeWhile(const TakeWhile&) = default; - class Iterator { + class Iterator + : public std::iterator> + { private: using iter_type = iterator_type; iterator_type sub_iter; @@ -123,4 +123,4 @@ namespace iter { } -#endif //ifndef TAKEWHILE__H__ +#endif From c459de9e517d8563fddaf01dbde0f05621faa201 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 24 Jan 2015 16:58:50 -0500 Subject: [PATCH 0796/1866] actually basic tests takewhile --- catchtest/test_takewhile.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/catchtest/test_takewhile.cpp b/catchtest/test_takewhile.cpp index 9b92b9ab..35bb40c6 100644 --- a/catchtest/test_takewhile.cpp +++ b/catchtest/test_takewhile.cpp @@ -30,6 +30,7 @@ TEST_CASE("takewhile: works with lambda, callable, and function pointer", SECTION("function pointer") { auto tw = takewhile(under_ten, ns); Vec v(std::begin(tw), std::end(tw)); - + Vec vc = {1, 3, 5}; + REQUIRE( v == vc ); } } From e422b8ae63fa87e6a7d17e4c394b6ad8490437a9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 24 Jan 2015 17:00:45 -0500 Subject: [PATCH 0797/1866] tests takewhile with different functor types --- catchtest/test_takewhile.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/catchtest/test_takewhile.cpp b/catchtest/test_takewhile.cpp index 35bb40c6..58a1bc52 100644 --- a/catchtest/test_takewhile.cpp +++ b/catchtest/test_takewhile.cpp @@ -33,4 +33,18 @@ TEST_CASE("takewhile: works with lambda, callable, and function pointer", Vec vc = {1, 3, 5}; REQUIRE( v == vc ); } + + SECTION("callable object") { + auto tw = takewhile(UnderTen{}, ns); + Vec v(std::begin(tw), std::end(tw)); + Vec vc = {1, 3, 5}; + REQUIRE( v == vc ); + } + + SECTION("lambda") { + auto tw = takewhile([](int i){ return i < 10; }, ns); + Vec v(std::begin(tw), std::end(tw)); + Vec vc = {1, 3, 5}; + REQUIRE( v == vc ); + } } From 111057d59e70e571ffb361cb2aa44f0ef18220f0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 24 Jan 2015 17:01:22 -0500 Subject: [PATCH 0798/1866] removes placement new from takewhile --- takewhile.hpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/takewhile.hpp b/takewhile.hpp index 5447f791..43ddc53d 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -49,18 +49,12 @@ namespace iter { private: using iter_type = iterator_type; iterator_type sub_iter; - const iterator_type sub_end; + iterator_type sub_end; FilterFunc filter_func; - // check if the current value is true under the predicate - // if it is not, set the sub_iter to the end using - // placement new to avoid the requirement of the iterator - // having an operator= void check_current() { if (!this->filter_func(*this->sub_iter)) { - this->sub_iter.~iter_type(); - new(&this->sub_iter) iterator_type( - this->sub_end); + this->sub_iter = this->sub_end; } } @@ -78,7 +72,7 @@ namespace iter { } } - iterator_deref operator*() const { + iterator_deref operator*() { return *this->sub_iter; } From 4dfce4c6736c8f9b26f5dce7342fd93742b7e118 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 24 Jan 2015 17:02:50 -0500 Subject: [PATCH 0799/1866] adds takewhile iter postfix ++ and == --- takewhile.hpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/takewhile.hpp b/takewhile.hpp index 43ddc53d..ef8d5409 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -33,7 +33,6 @@ namespace iter { friend TakeWhile> takewhile( FF, std::initializer_list); - // Value constructor for use only in the takewhile function TakeWhile(FilterFunc filter_func, Container container) : container(std::forward(container)), filter_func(filter_func) @@ -47,7 +46,6 @@ namespace iter { iterator_traits_deref> { private: - using iter_type = iterator_type; iterator_type sub_iter; iterator_type sub_end; FilterFunc filter_func; @@ -59,7 +57,7 @@ namespace iter { } public: - Iterator (iterator_type iter, + Iterator(iterator_type iter, iterator_type end, FilterFunc filter_func) : sub_iter{iter}, @@ -82,9 +80,20 @@ namespace 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() { @@ -101,7 +110,6 @@ namespace iter { }; - // Helper function to instantiate a TakeWhile template TakeWhile takewhile( FilterFunc filter_func, Container&& container) { From fcbd18159b2c5772df0ad19bcd8192ad2bf56a7a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 24 Jan 2015 17:06:14 -0500 Subject: [PATCH 0800/1866] tests takewhile with empty iterable --- catchtest/test_takewhile.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/catchtest/test_takewhile.cpp b/catchtest/test_takewhile.cpp index 58a1bc52..ff3f42b5 100644 --- a/catchtest/test_takewhile.cpp +++ b/catchtest/test_takewhile.cpp @@ -48,3 +48,9 @@ TEST_CASE("takewhile: works with lambda, callable, and function pointer", REQUIRE( v == vc ); } } + +TEST_CASE("takewhile: empty iterable is empty", "[takewhile]") { + Vec ns{}; + auto tw = takewhile(under_ten, ns); + REQUIRE( std::begin(tw) == std::end(tw) ); +} From 333b6743157b85771c88d15e86b8285e4256d7c2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 24 Jan 2015 17:15:05 -0500 Subject: [PATCH 0801/1866] tests takewhile when first element fails predicate --- catchtest/test_takewhile.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/catchtest/test_takewhile.cpp b/catchtest/test_takewhile.cpp index ff3f42b5..88d755ff 100644 --- a/catchtest/test_takewhile.cpp +++ b/catchtest/test_takewhile.cpp @@ -54,3 +54,20 @@ TEST_CASE("takewhile: empty iterable is empty", "[takewhile]") { auto tw = takewhile(under_ten, ns); REQUIRE( std::begin(tw) == std::end(tw) ); } + +TEST_CASE("takewhile: when first element fails predicate, it's empty" + "[takewhile]") { + SECTION("First element is only element") { + Vec ns = {20}; + auto tw = takewhile(under_ten, ns); + REQUIRE( std::begin(tw) == std::end(tw) ); + } + + SECTION("First element followed by elements that pass") { + Vec ns = {20, 1, 1}; + auto tw = takewhile(under_ten, ns); + REQUIRE( std::begin(tw) == std::end(tw) ); + } +} + + From a0a17ba9c329e75a4819094cd3117721acf28d2f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 24 Jan 2015 17:15:35 -0500 Subject: [PATCH 0802/1866] builds takewhile test --- catchtest/SConstruct | 2 ++ 1 file changed, 2 insertions(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index aebe1c81..4fac7a84 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -37,6 +37,8 @@ progs = Split( reversed sliding_window + + takewhile ''' ) From 3c2696e7fb4eadd1aba60659a1dd8fe24cec9ef7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 24 Jan 2015 17:17:49 -0500 Subject: [PATCH 0803/1866] tests that takewhile moves and binds correctly --- catchtest/test_takewhile.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/catchtest/test_takewhile.cpp b/catchtest/test_takewhile.cpp index 88d755ff..80189737 100644 --- a/catchtest/test_takewhile.cpp +++ b/catchtest/test_takewhile.cpp @@ -70,4 +70,11 @@ TEST_CASE("takewhile: when first element fails predicate, it's empty" } } - +TEST_CASE("takewhile: moves rvalues, binds to lvalues", "[takewhile]") { + itertest::BasicIterable bi{1, 2}; + takewhile(under_ten, bi); + REQUIRE_FALSE( bi.was_moved_from() ); + + takewhile(under_ten, std::move(bi)); + REQUIRE( bi.was_moved_from() ); +} From fe9af2178cde28f0a9e6bf91883c72a1adc705d0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 24 Jan 2015 17:21:46 -0500 Subject: [PATCH 0804/1866] tests that takewhile doesn't copy elements --- catchtest/test_takewhile.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/catchtest/test_takewhile.cpp b/catchtest/test_takewhile.cpp index 80189737..9394d32c 100644 --- a/catchtest/test_takewhile.cpp +++ b/catchtest/test_takewhile.cpp @@ -78,3 +78,13 @@ TEST_CASE("takewhile: moves rvalues, binds to lvalues", "[takewhile]") { takewhile(under_ten, std::move(bi)); REQUIRE( bi.was_moved_from() ); } + +TEST_CASE("takewhile: with iterable doesn't move or copy elements", + "[takewhile]") { + constexpr std::array arr{{{6}, {7}, {8}}}; + auto func = + [](const itertest::SolidInt& si){return si.getint() < 10;}; + for (auto&& i : takewhile(func, arr)) { + (void)i; + } +} From 5f0cc36f275bcda0d510f7e26373932df4540be6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 25 Jan 2015 21:18:49 -0500 Subject: [PATCH 0805/1866] tests range with floats --- catchtest/test_range.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/catchtest/test_range.cpp b/catchtest/test_range.cpp index 9a0bee9e..8b4b0150 100644 --- a/catchtest/test_range.cpp +++ b/catchtest/test_range.cpp @@ -144,3 +144,12 @@ TEST_CASE("range: works with a variable start, stop, and step", "[range]") { } } + +using FVec = const std::vector; + +TEST_CASE("range: using doubles", "[range]") { + auto r = range(5.0); + FVec fv(std::begin(r), std::end(r)); + FVec fvc = {0.0, 1.0, 2.0, 3.0, 4.0}; + REQUIRE( fv == fvc ); +} From c3a9438418267ed99d33a3a9de3646b0e2e073b9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 25 Jan 2015 21:34:14 -0500 Subject: [PATCH 0806/1866] adds float specific range tests --- catchtest/test_range.cpp | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/catchtest/test_range.cpp b/catchtest/test_range.cpp index 8b4b0150..fbf50298 100644 --- a/catchtest/test_range.cpp +++ b/catchtest/test_range.cpp @@ -153,3 +153,40 @@ TEST_CASE("range: using doubles", "[range]") { FVec fvc = {0.0, 1.0, 2.0, 3.0, 4.0}; REQUIRE( fv == fvc ); } + +TEST_CASE("range: using doubles with start and stop", "[range]") { + auto r = range(5.0, 10.0); + FVec fv(std::begin(r), std::end(r)); + FVec fvc = {5.0, 6.0, 7.0, 8.0, 9.0}; + REQUIRE( fv == fvc ); +} + +TEST_CASE("range: using doubles with start, stop and step", "[range]") { + auto r = range(1.0, 4.0, 0.5); + FVec fv(std::begin(r), std::end(r)); + FVec fvc = {1.0, 1.5, 2.0, 2.5, 3.0, 3.5}; + REQUIRE( fv == fvc ); +} + +TEST_CASE("range: using doubles with negative", "[range]") { + auto r = range(0.5, -2.0, -0.5); + FVec fv(std::begin(r), std::end(r)); + FVec fvc = {0.5, 0.0, -0.5, -1.0, -1.5}; + REQUIRE( fv == fvc ); +} + +TEST_CASE("range: using doubles with uneven step", "[range]") { + auto r = range(0.0, 1.75, 0.5); + FVec fv(std::begin(r), std::end(r)); + FVec fvc = {0.0, 0.5, 1.0, 1.5}; + REQUIRE( fv == fvc ); +} + +TEST_CASE("range: using doubles detects empty ranges", "[range]") { + auto r1 = range(0.0, -1.0); + REQUIRE(std::begin(r1) == std::end(r1)); + + auto r2 = range(0.0, 1.0, -1.0); + REQUIRE(std::begin(r2) == std::end(r2)); +} + From f5302c90e5a72a51878df72c1096fc650d6ca881 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 25 Jan 2015 21:34:27 -0500 Subject: [PATCH 0807/1866] Divides range into float and non-float versions Since repeatedly adding a value to a floating point number will accumulate inaccuracies, a special version of Range was needed. The normal version is the same, but the float version will calculate the current value on each increment using start + (steps_taken + step_size). This will reduce the inaccuracies by preventing them from building up. --- range.hpp | 117 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 96 insertions(+), 21 deletions(-) diff --git a/range.hpp b/range.hpp index 6366e727..3ce9784c 100644 --- a/range.hpp +++ b/range.hpp @@ -23,27 +23,27 @@ namespace iter { // Thrown when step 0 occurs class RangeException : public std::exception { - virtual const char *what() const noexcept { + const char *what() const noexcept override { return "range step must be non-zero"; } }; - //Forward declarations of Enumerable and enumerate - template + template class Range; - template - Range range(T); - template - Range range(T, T); - template - Range range(T, T, T); + template ::value> + Range range(T); + template ::value> + Range range(T, T); + template ::value> + Range range(T, T, T); + // General version for everything not a float template - class Range { - friend Range range(T); - friend Range range(T, T); - friend Range range(T, T, T); + class Range { + friend Range range(T); + friend Range range(T, T); + friend Range range(T, T, T); private: const T start; const T stop; @@ -62,8 +62,6 @@ namespace iter { { } public: - Range() = delete; - Range(const Range&) = default; class Iterator : public std::iterator { @@ -140,19 +138,96 @@ namespace iter { } }; - + // This specialization is used for floating point types. Instead of + // adding one "step" each time ++ is called on the iterator, the value + // is recalculated as start + (steps_taken + step_size) to avoid + // accumulating floating point inaccuracies template - Range range(T stop) { + class Range { + friend Range range(T); + friend Range range(T, T); + friend Range range(T, T, T); + private: + const T start; + const T stop; + const T step; + + Range(T stop) + : start{0}, + stop{stop}, + step{1} + { } + + Range(T start, T stop, T step =1) + : start{start}, + stop{stop}, + step{step} + { } + public: + class Iterator + : public std::iterator + { + private: + T start; + T value; + T step; + unsigned long steps_taken =0; + + public: + Iterator(T start, T step) + : start{start}, + value{start}, + step{step} + { } + + bool operator!=(const Iterator& other) const { + return !(this->step > 0 && this->value >= other.value) + && !(this->step < 0 && this->value <= other.value); + } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } + + T operator*() const { + return this->value; + } + + Iterator& operator++() { + ++this->steps_taken; + this->value = this->start + + (this->step * this->steps_taken); + return *this; + } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + }; + + Iterator begin() const { + return {start, step}; + } + + Iterator end() const { + return {stop, step}; + } + }; + + template + Range range(T stop) { return {stop}; } - template - Range range(T start, T stop) { + template + Range range(T start, T stop) { return {start, stop}; } - template - Range range(T start, T stop, T step) { + template + Range range(T start, T stop, T step) { if (step == 0) { throw RangeException{}; } From 567121d8dc914a68df3d118073563b67caf128f8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 25 Jan 2015 21:36:13 -0500 Subject: [PATCH 0808/1866] count deduces return type --- count.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/count.hpp b/count.hpp index 579edceb..e0bc7cd0 100644 --- a/count.hpp +++ b/count.hpp @@ -9,13 +9,13 @@ namespace iter { using DefaultRangeType = long; - Range count() { + auto count() -> decltype(range(DefaultRangeType(0), DefaultRangeType(0))) { return range(DefaultRangeType(0), std::numeric_limits::max()); } template - Range count(T start, T step) { + auto count(T start, T step) -> decltype(range(start, start, start)) { // 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 - Range count(T start) { + auto count(T start) -> decltype(range(start, start)) { return count(start, T(1)); } } From a4298d665a52e7ea1d19b95e015c9b6ca8eb5bf3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 Jan 2015 14:47:33 -0500 Subject: [PATCH 0809/1866] removes reference in imap iterator_traits --- imap.hpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/imap.hpp b/imap.hpp index ef0727fd..9df55a1a 100644 --- a/imap.hpp +++ b/imap.hpp @@ -87,15 +87,11 @@ namespace iter { 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 - : public std::iterator + : public std::iterator::type > { private: MapFunc map_func; From 4df5e5a37f4a0fa688aeb7a6b8d02a49a10e1c42 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 Jan 2015 14:53:07 -0500 Subject: [PATCH 0810/1866] tests takewhile when everything passes --- catchtest/test_takewhile.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/catchtest/test_takewhile.cpp b/catchtest/test_takewhile.cpp index 9394d32c..aae3f481 100644 --- a/catchtest/test_takewhile.cpp +++ b/catchtest/test_takewhile.cpp @@ -49,6 +49,13 @@ TEST_CASE("takewhile: works with lambda, callable, and function pointer", } } +TEST_CASE("takewhile: everything passes predicate", "[takewhile]") { + Vec ns{1, 2, 3}; + auto tw = takewhile(under_ten, ns); + Vec v(std::begin(tw), std::end(tw)); + Vec vc = {1, 2, 3}; +} + TEST_CASE("takewhile: empty iterable is empty", "[takewhile]") { Vec ns{}; auto tw = takewhile(under_ten, ns); @@ -81,7 +88,7 @@ TEST_CASE("takewhile: moves rvalues, binds to lvalues", "[takewhile]") { TEST_CASE("takewhile: with iterable doesn't move or copy elements", "[takewhile]") { - constexpr std::array arr{{{6}, {7}, {8}}}; + constexpr std::array arr{{{8}, {9}, {10}}}; auto func = [](const itertest::SolidInt& si){return si.getint() < 10;}; for (auto&& i : takewhile(func, arr)) { From a6c2976f9b5d133499340724a3c1a27019904c40 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 Jan 2015 14:53:24 -0500 Subject: [PATCH 0811/1866] checks for end in check_current() --- takewhile.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/takewhile.hpp b/takewhile.hpp index ef8d5409..de5c7178 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -51,7 +51,8 @@ namespace iter { FilterFunc filter_func; void check_current() { - if (!this->filter_func(*this->sub_iter)) { + if (this->sub_iter != this->sub_end + && !this->filter_func(*this->sub_iter)) { this->sub_iter = this->sub_end; } } From 091e4f948535b8fbbf959393ba4e4b6941bb272e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 Jan 2015 14:55:45 -0500 Subject: [PATCH 0812/1866] eliminates useless specifications in dropwhile --- dropwhile.hpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index 28e823eb..0f2725cd 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -9,7 +9,6 @@ namespace iter { - //Forward declarations of DropWhile and dropwhile template class DropWhile; @@ -33,16 +32,12 @@ namespace iter { friend DropWhile> dropwhile( FF, std::initializer_list); - // Value constructor for use only in the dropwhile function DropWhile(FilterFunc filter_func, Container container) : container(std::forward(container)), filter_func(filter_func) { } - DropWhile() = delete; - DropWhile& operator=(const DropWhile&) = delete; public: - DropWhile(const DropWhile&) = default; class Iterator : public std::iterator> @@ -109,7 +104,6 @@ namespace iter { }; - // Helper function to instantiate a DropWhile template DropWhile dropwhile( FilterFunc filter_func, Container&& container) { From 9ae6355088527a07af386ccdf2f2b895e97071de Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 Jan 2015 14:59:14 -0500 Subject: [PATCH 0813/1866] slight alteration on range differentiation instead of two specializations, have IsFloat default to false so Range still works. this shouldn't affect too much though. --- range.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/range.hpp b/range.hpp index 3ce9784c..f0e7048c 100644 --- a/range.hpp +++ b/range.hpp @@ -28,7 +28,7 @@ namespace iter { } }; - template + template class Range; template ::value> @@ -39,8 +39,8 @@ namespace iter { Range range(T, T, T); // General version for everything not a float - template - class Range { + template + class Range { friend Range range(T); friend Range range(T, T); friend Range range(T, T, T); From 1c2a4bbea86ed71ae4e5cf241f9c2c833d39c20f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 Jan 2015 15:11:22 -0500 Subject: [PATCH 0814/1866] tests unique_everseen with adjacent duplicates --- catchtest/test_unique_everseen.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 catchtest/test_unique_everseen.cpp diff --git a/catchtest/test_unique_everseen.cpp b/catchtest/test_unique_everseen.cpp new file mode 100644 index 00000000..c8c87317 --- /dev/null +++ b/catchtest/test_unique_everseen.cpp @@ -0,0 +1,21 @@ +#include + +#include "helpers.hpp" + +#include +#include +#include + +#include "catch.hpp" + +using iter::unique_everseen; + +using Vec = const std::vector; + +TEST_CASE("unique everseen: adjacent repeating values", "[unique_everseen]") { + Vec ns = {1,1,1,2,2,3,4,4,5,6,7,8,8,8,8,9,9}; + auto ue = unique_everseen(ns); + Vec v(std::begin(ue), std::end(ue)); + Vec vc = {1,2,3,4,5,6,7,8,9}; + REQUIRE( v == vc ); +} From 10a4e72343f9973a7b2a9f2745c7db7551ce05d6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 Jan 2015 15:13:24 -0500 Subject: [PATCH 0815/1866] replaces remove_reference with decay --- unique_everseen.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unique_everseen.hpp b/unique_everseen.hpp index 77124c8d..066107e4 100644 --- a/unique_everseen.hpp +++ b/unique_everseen.hpp @@ -19,7 +19,7 @@ namespace iter -> Filter)>,Container> { using elem_t = iterator_deref; - std::unordered_set::type> elem_seen; + std::unordered_set::type> elem_seen; std::function func = //has to be captured by value because it goes out of scope when the From 4eb2423252772e26f60491c322a7051b06bebdfb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 Jan 2015 15:15:33 -0500 Subject: [PATCH 0816/1866] tests unique_everseen with non-adjacent duplicates --- catchtest/test_unique_everseen.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/catchtest/test_unique_everseen.cpp b/catchtest/test_unique_everseen.cpp index c8c87317..359ad50a 100644 --- a/catchtest/test_unique_everseen.cpp +++ b/catchtest/test_unique_everseen.cpp @@ -13,9 +13,18 @@ using iter::unique_everseen; using Vec = const std::vector; TEST_CASE("unique everseen: adjacent repeating values", "[unique_everseen]") { - Vec ns = {1,1,1,2,2,3,4,4,5,6,7,8,8,8,8,9,9}; - auto ue = unique_everseen(ns); - Vec v(std::begin(ue), std::end(ue)); - Vec vc = {1,2,3,4,5,6,7,8,9}; - REQUIRE( v == vc ); + Vec ns = {1,1,1,2,2,3,4,4,5,6,7,8,8,8,8,9,9}; + auto ue = unique_everseen(ns); + Vec v(std::begin(ue), std::end(ue)); + Vec vc = {1,2,3,4,5,6,7,8,9}; + REQUIRE( v == vc ); +} + +TEST_CASE("unique everseen: nonadjacent repeating values", + "[unique_everseen]") { + Vec ns = {1,2,3,4,3,2,1,5,6}; + auto ue = unique_everseen(ns); + Vec v(std::begin(ue), std::end(ue)); + Vec vc = {1,2,3,4,5,6}; + REQUIRE( v == vc ); } From 29c823391d3a8fe3adc7d4a44abc187333536d95 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 Jan 2015 15:19:47 -0500 Subject: [PATCH 0817/1866] tests unique_everseen binds and moves correctly --- catchtest/test_unique_everseen.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/catchtest/test_unique_everseen.cpp b/catchtest/test_unique_everseen.cpp index 359ad50a..31e712a2 100644 --- a/catchtest/test_unique_everseen.cpp +++ b/catchtest/test_unique_everseen.cpp @@ -28,3 +28,13 @@ TEST_CASE("unique everseen: nonadjacent repeating values", Vec vc = {1,2,3,4,5,6}; REQUIRE( v == vc ); } + +TEST_CASE("unique everseen: moves rvalues, binds to lvalues", + "[unique_everseen]") { + itertest::BasicIterable bi{1, 2}; + unique_everseen(bi); + REQUIRE_FALSE( bi.was_moved_from() ); + + unique_everseen(std::move(bi)); + REQUIRE( bi.was_moved_from() ); +} From 5e13dfc60b2a1621a6c194e2036ee992ec12096b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 Jan 2015 15:20:09 -0500 Subject: [PATCH 0818/1866] builds unique_everseen test --- catchtest/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index 4fac7a84..c81a1b97 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -39,6 +39,7 @@ progs = Split( sliding_window takewhile + unique_everseen ''' ) From 9ffe3dac17f0942ba864dc78c9885981f56eb7c2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 Jan 2015 15:24:27 -0500 Subject: [PATCH 0819/1866] changes everseen header --- unique_everseen.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/unique_everseen.hpp b/unique_everseen.hpp index 066107e4..ec95eb34 100644 --- a/unique_everseen.hpp +++ b/unique_everseen.hpp @@ -1,5 +1,5 @@ -#ifndef UNIQUE_EVERSEEN_HPP -#define UNIQUE_EVERSEEN_HPP +#ifndef ITER_UNIQUE_EVERSEEN_HPP_ +#define ITER_UNIQUE_EVERSEEN_HPP_ #include "iterbase.hpp" #include "filter.hpp" @@ -54,4 +54,4 @@ namespace iter } } -#endif //UNIQUE_EVERSEEN_HPP +#endif From bf345ac0a6be8e5b7e0f3c514bd0fd939e58d512 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 Jan 2015 15:34:24 -0500 Subject: [PATCH 0820/1866] initial unique justseen tests --- catchtest/test_unique_justseen.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 catchtest/test_unique_justseen.cpp diff --git a/catchtest/test_unique_justseen.cpp b/catchtest/test_unique_justseen.cpp new file mode 100644 index 00000000..0ba88b64 --- /dev/null +++ b/catchtest/test_unique_justseen.cpp @@ -0,0 +1,21 @@ +#include + +#include "helpers.hpp" + +#include +#include +#include + +#include "catch.hpp" + +using iter::unique_justseen; + +using Vec = const std::vector; + +TEST_CASE("unique justseen: adjacent repeating values", "[unique_justseen]") { + Vec ns = {1,1,1,2,2,3,4,4,5,6,7,8,8,8,8,9,9}; + auto ue = unique_justseen(ns); + Vec v(std::begin(ue), std::end(ue)); + Vec vc = {1,2,3,4,5,6,7,8,9}; + REQUIRE( v == vc ); +} From e233994718d75ab232cb795f6d4394b1b6e829c2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 Jan 2015 15:44:34 -0500 Subject: [PATCH 0821/1866] tests unique_justseen with non-adjacent dupes --- catchtest/test_unique_justseen.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/catchtest/test_unique_justseen.cpp b/catchtest/test_unique_justseen.cpp index 0ba88b64..e8a09b1a 100644 --- a/catchtest/test_unique_justseen.cpp +++ b/catchtest/test_unique_justseen.cpp @@ -19,3 +19,19 @@ TEST_CASE("unique justseen: adjacent repeating values", "[unique_justseen]") { Vec vc = {1,2,3,4,5,6,7,8,9}; REQUIRE( v == vc ); } + +TEST_CASE("unique justseen: some repeating values", "[unique_justseen]") { + Vec ns = {1,2,2,3,4,4,5,6,6}; + auto ue = unique_justseen(ns); + Vec v(std::begin(ue), std::end(ue)); + Vec vc = {1,2,3,4,5,6}; + REQUIRE( v == vc ); +} + +TEST_CASE("unique justseen: doesn't omit non-adjacent duplicates", + "[unique_justseen]") { + Vec ns = {1,2,1,2,1}; + auto ue = unique_justseen(ns); + Vec v(std::begin(ue), std::end(ue)); + REQUIRE( v == ns ); +} From 0e76af74277a77cad8034d31629aae888aecce68 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 Jan 2015 15:46:41 -0500 Subject: [PATCH 0822/1866] builds unique_justseen test --- catchtest/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index c81a1b97..603ec080 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -40,6 +40,7 @@ progs = Split( takewhile unique_everseen + unique_justseen ''' ) From 34f151bc038a2d324e816a755fae9acb647e1e23 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 Jan 2015 23:06:19 -0500 Subject: [PATCH 0823/1866] groupby does end-of-group check in ++ This way it's only done once, and it avoids constness issues arising elsewhere when it was in operator!= --- groupby.hpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index 79960c8b..9ac0bfb1 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -107,14 +107,14 @@ namespace iter { } bool exhausted() const { - return this->sub_iter == this->sub_end; + return !(this->sub_iter != this->sub_end); } iterator_deref current() { return *this->sub_iter; } - key_func_ret next_key() const { + key_func_ret next_key() { return this->key_func(*this->sub_iter); } }; @@ -173,7 +173,7 @@ namespace iter { const key_func_ret key; const Group& group; - bool not_at_end() const { + bool not_at_end() { return !this->group.owner.exhausted()&& this->group.owner.next_key() == this->key; } @@ -188,12 +188,15 @@ namespace iter { GroupIterator(const GroupIterator&) = default; bool operator!=(const GroupIterator&) const { + return !this->group.completed; +#if 0 if (this->not_at_end()) { return true; } else { this->group.completed = true; return false; } +#endif } bool operator==(const GroupIterator& other) const { @@ -202,6 +205,9 @@ namespace iter { GroupIterator& operator++() { this->group.owner.increment_iterator(); + if (!this->not_at_end()) { + this->group.completed = true; + } return *this; } @@ -246,7 +252,6 @@ namespace iter { template class ItemReturner { public: - ItemReturner() = default; iterator_deref operator() ( iterator_deref item) const { return item; From 6392b1cf180c30e1a94fe6c3f697dc5bb51d6955 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 Jan 2015 23:11:47 -0500 Subject: [PATCH 0824/1866] tests unique_justseen binds and moves correctly --- catchtest/test_unique_justseen.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/catchtest/test_unique_justseen.cpp b/catchtest/test_unique_justseen.cpp index e8a09b1a..fcb9067b 100644 --- a/catchtest/test_unique_justseen.cpp +++ b/catchtest/test_unique_justseen.cpp @@ -30,8 +30,17 @@ TEST_CASE("unique justseen: some repeating values", "[unique_justseen]") { TEST_CASE("unique justseen: doesn't omit non-adjacent duplicates", "[unique_justseen]") { - Vec ns = {1,2,1,2,1}; + Vec ns = {1,2,3,2,1,2,3,2,1}; auto ue = unique_justseen(ns); Vec v(std::begin(ue), std::end(ue)); REQUIRE( v == ns ); } + +TEST_CASE("unique justseen: moves and binds correctly", "[unique_justseen]") { + itertest::BasicIterable bi{1, 2}; + unique_justseen(bi); + REQUIRE_FALSE( bi.was_moved_from() ); + + unique_justseen(std::move(bi)); + REQUIRE( bi.was_moved_from() ); +} From 50bb692149198ccd274392021defdfbf89499315 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 Jan 2015 23:38:29 -0500 Subject: [PATCH 0825/1866] tests zip_longest --- catchtest/test_zip_longest.cpp | 48 ++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 catchtest/test_zip_longest.cpp diff --git a/catchtest/test_zip_longest.cpp b/catchtest/test_zip_longest.cpp new file mode 100644 index 00000000..e603d655 --- /dev/null +++ b/catchtest/test_zip_longest.cpp @@ -0,0 +1,48 @@ +#include + +#include "helpers.hpp" + +#include +#include +#include +#include +#include +#include + +#include "catch.hpp" + +using iter::zip_longest; + +TEST_CASE("zip longest: correctly detects longest at any position", + "[zip_longest]") { + using TP = std::tuple; + using ResVec = std::vector; + + const std::vector ivec{2, 4, 6, 8, 10, 12}; + const std::vector svec{"abc", "def", "xyz"}; + const std::string str{"hello"}; + + ResVec results; + ResVec rc; + + SECTION("longest first") { + for (auto&& t : zip_longest(ivec, svec, str)) { + results.emplace_back( + std::get<0>(t).get_value_or(-1), + std::get<1>(t).get_value_or(""), + std::get<2>(t).get_value_or('\0') + ); + } + rc = ResVec { + TP{2, "abc", 'h'}, + TP{4, "def", 'e'}, + TP{6, "xyz", 'l'}, + TP{8, "", 'l'}, + TP{10, "", 'o'}, + TP{12, "", '\0'} + }; + } + + + REQUIRE( results == rc ); +} From d591165102fad8c38a233ad222fe318dbeb68a36 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 Jan 2015 23:51:06 -0500 Subject: [PATCH 0826/1866] simplifies first zip_longest test --- catchtest/test_zip_longest.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/catchtest/test_zip_longest.cpp b/catchtest/test_zip_longest.cpp index e603d655..3fc01eaa 100644 --- a/catchtest/test_zip_longest.cpp +++ b/catchtest/test_zip_longest.cpp @@ -12,10 +12,12 @@ #include "catch.hpp" using iter::zip_longest; +template +using opt = boost::optional; TEST_CASE("zip longest: correctly detects longest at any position", "[zip_longest]") { - using TP = std::tuple; + using TP = std::tuple, opt, opt>; using ResVec = std::vector; const std::vector ivec{2, 4, 6, 8, 10, 12}; @@ -27,19 +29,15 @@ TEST_CASE("zip longest: correctly detects longest at any position", SECTION("longest first") { for (auto&& t : zip_longest(ivec, svec, str)) { - results.emplace_back( - std::get<0>(t).get_value_or(-1), - std::get<1>(t).get_value_or(""), - std::get<2>(t).get_value_or('\0') - ); + results.push_back(t); } rc = ResVec { - TP{2, "abc", 'h'}, - TP{4, "def", 'e'}, - TP{6, "xyz", 'l'}, - TP{8, "", 'l'}, - TP{10, "", 'o'}, - TP{12, "", '\0'} + TP{ivec[0], svec[0], str[0]}, + TP{ivec[1], svec[1], str[1]}, + TP{ivec[2], svec[2], str[2]}, + TP{ivec[3], {}, str[3]}, + TP{ivec[4], {}, str[4]}, + TP{ivec[5], {}, {} } }; } From 90fa2defa28cf5e503c4f31226e3242b7fe9eaaf Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 00:01:28 -0500 Subject: [PATCH 0827/1866] further simplifies zip_longest test --- catchtest/test_zip_longest.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/catchtest/test_zip_longest.cpp b/catchtest/test_zip_longest.cpp index 3fc01eaa..bf6307d5 100644 --- a/catchtest/test_zip_longest.cpp +++ b/catchtest/test_zip_longest.cpp @@ -28,9 +28,8 @@ TEST_CASE("zip longest: correctly detects longest at any position", ResVec rc; SECTION("longest first") { - for (auto&& t : zip_longest(ivec, svec, str)) { - results.push_back(t); - } + auto zl = zip_longest(ivec, svec, str); + results = ResVec(std::begin(zl), std::end(zl)); rc = ResVec { TP{ivec[0], svec[0], str[0]}, TP{ivec[1], svec[1], str[1]}, @@ -41,6 +40,5 @@ TEST_CASE("zip longest: correctly detects longest at any position", }; } - REQUIRE( results == rc ); } From 9468b53c64c498e24b4f845421e80f9ac2f2d4d1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 00:01:43 -0500 Subject: [PATCH 0828/1866] zip_longest iters inherit from std::iterator --- zip_longest.hpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/zip_longest.hpp b/zip_longest.hpp index f3fd8014..803c809e 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -28,6 +28,10 @@ namespace iter { friend class ZippedLongest; private: + using OptType = boost::optional>; + using ZipIterDeref = + std::tuple>...>; Container container; ZippedLongest rest_zipped; ZippedLongest(Container container, RestContainers&&... rest) @@ -36,11 +40,12 @@ namespace iter { { } public: - class Iterator { + class Iterator + : public std::iterator + { private: using RestIter = typename ZippedLongest::Iterator; - using OptType = boost::optional>; iterator_type iter; iterator_type end; @@ -69,11 +74,7 @@ namespace iter { this->rest_iter != other.rest_iter; } - auto operator*() -> - decltype(std::tuple_cat( - std::tuple{OptType{*this->iter}}, - *this->rest_iter)) - { + ZipIterDeref operator*() { if (this->iter != this->end) { return std::tuple_cat( std::tuple{OptType{*this->iter}}, @@ -111,6 +112,8 @@ namespace iter { friend class ZippedLongest; private: + using OptType = boost::optional>; + Container container; ZippedLongest(Container container) : container(std::forward(container)) @@ -118,9 +121,11 @@ namespace iter { public: - class Iterator { + class Iterator + : public std::iterator> + { private: - using OptType = boost::optional>; iterator_type iter; iterator_type end; public: From e958db8d6c735e62a21a3252957577c74c89ea47 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 00:06:47 -0500 Subject: [PATCH 0829/1866] adds alias for getting optional type optional> that is. --- zip_longest.hpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/zip_longest.hpp b/zip_longest.hpp index 803c809e..affb0d5d 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -1,5 +1,5 @@ -#ifndef ZIP_LONGEST_HPP_ -#define ZIP_LONGEST_HPP_ +#ifndef ITER_ZIP_LONGEST_HPP_ +#define ITER_ZIP_LONGEST_HPP_ #include "iterbase.hpp" @@ -10,6 +10,10 @@ namespace iter { + + template + using OptIterDeref = boost::optional>; + template class ZippedLongest; @@ -28,10 +32,10 @@ namespace iter { friend class ZippedLongest; private: - using OptType = boost::optional>; + using OptType = OptIterDeref; using ZipIterDeref = - std::tuple>...>; + std::tuple...>; + Container container; ZippedLongest rest_zipped; ZippedLongest(Container container, RestContainers&&... rest) @@ -112,7 +116,7 @@ namespace iter { friend class ZippedLongest; private: - using OptType = boost::optional>; + using OptType = OptIterDeref; Container container; ZippedLongest(Container container) @@ -172,4 +176,4 @@ namespace iter { } } -#endif // #ifndef ZIP_LONGEST_HPP_ +#endif From 767f8c9a6ec665e7fb6c2a7f3307bd21df11c4fb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 12:40:56 -0500 Subject: [PATCH 0830/1866] direct initialization-list for tuple --- zip_longest.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/zip_longest.hpp b/zip_longest.hpp index affb0d5d..88886666 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -4,6 +4,7 @@ #include "iterbase.hpp" #include +#include // TODO remove #include #include #include @@ -81,11 +82,11 @@ namespace iter { ZipIterDeref operator*() { if (this->iter != this->end) { return std::tuple_cat( - std::tuple{OptType{*this->iter}}, + std::tuple{{*this->iter}}, *this->rest_iter); } else { return std::tuple_cat( - std::tuple{OptType{}}, + std::tuple{{}}, *this->rest_iter); } } @@ -153,9 +154,9 @@ namespace iter { std::tuple operator*() { if (this->iter != this->end) { - return std::tuple{OptType{*this->iter}}; + return std::tuple{{*this->iter}}; } - return std::tuple{OptType{}}; + return std::tuple{{}}; } }; From 2b03d1b6dbea24746a2c9b733cffbb6c843f90cb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 12:41:52 -0500 Subject: [PATCH 0831/1866] tests zip_longest with longest in different places --- catchtest/test_zip_longest.cpp | 70 ++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 16 deletions(-) diff --git a/catchtest/test_zip_longest.cpp b/catchtest/test_zip_longest.cpp index bf6307d5..bb73dbb3 100644 --- a/catchtest/test_zip_longest.cpp +++ b/catchtest/test_zip_longest.cpp @@ -8,37 +8,75 @@ #include #include #include +#include +#include #include "catch.hpp" using iter::zip_longest; -template -using opt = boost::optional; + + +template +using const_opt_tuple = std::tuple...>; TEST_CASE("zip longest: correctly detects longest at any position", "[zip_longest]") { - using TP = std::tuple, opt, opt>; - using ResVec = std::vector; const std::vector ivec{2, 4, 6, 8, 10, 12}; const std::vector svec{"abc", "def", "xyz"}; const std::string str{"hello"}; - ResVec results; - ResVec rc; - SECTION("longest first") { + using TP = const_opt_tuple; + using ResVec = std::vector; + auto zl = zip_longest(ivec, svec, str); - results = ResVec(std::begin(zl), std::end(zl)); - rc = ResVec { - TP{ivec[0], svec[0], str[0]}, - TP{ivec[1], svec[1], str[1]}, - TP{ivec[2], svec[2], str[2]}, - TP{ivec[3], {}, str[3]}, - TP{ivec[4], {}, str[4]}, - TP{ivec[5], {}, {} } + ResVec results(std::begin(zl), std::end(zl)); + ResVec rc = { + TP{{ivec[0]}, {svec[0]}, {str[0]}}, + TP{{ivec[1]}, {svec[1]}, {str[1]}}, + TP{{ivec[2]}, {svec[2]}, {str[2]}}, + TP{{ivec[3]}, {}, {str[3]}}, + TP{{ivec[4]}, {}, {str[4]}}, + TP{{ivec[5]}, {}, {} } + }; + + REQUIRE( results == rc ); + } + + SECTION("longest in middle") { + using TP = const_opt_tuple; + using ResVec = std::vector; + + auto zl = zip_longest(svec, ivec, str); + ResVec results(std::begin(zl), std::end(zl)); + ResVec rc = { + TP{{svec[0]}, {ivec[0]}, {str[0]}}, + TP{{svec[1]}, {ivec[1]}, {str[1]}}, + TP{{svec[2]}, {ivec[2]}, {str[2]}}, + TP{{}, {ivec[3]}, {str[3]}}, + TP{{}, {ivec[4]}, {str[4]}}, + TP{{}, {ivec[5]}, {} } }; + + REQUIRE( results == rc ); } - REQUIRE( results == rc ); + SECTION("longest at end") { + using TP = const_opt_tuple; + using ResVec = std::vector; + + auto zl = zip_longest(svec, str, ivec); + ResVec results(std::begin(zl), std::end(zl)); + ResVec rc = { + TP{{svec[0]}, {str[0]}, {ivec[0]}}, + TP{{svec[1]}, {str[1]}, {ivec[1]}}, + TP{{svec[2]}, {str[2]}, {ivec[2]}}, + TP{{}, {str[3]}, {ivec[3]}}, + TP{{}, {str[4]}, {ivec[4]}}, + TP{{}, {}, {ivec[5]}} + }; + + REQUIRE( results == rc ); + } } From b8cd2c1335e721d2a4c18dd8487a0c449fea6856 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 12:42:23 -0500 Subject: [PATCH 0832/1866] makes optionals printable I had to reopen boost for this to work, hopefully this won't be too disasterous down the road. --- catchtest/test_zip_longest.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/catchtest/test_zip_longest.cpp b/catchtest/test_zip_longest.cpp index bb73dbb3..6a2afbc2 100644 --- a/catchtest/test_zip_longest.cpp +++ b/catchtest/test_zip_longest.cpp @@ -15,6 +15,18 @@ using iter::zip_longest; +// reopening boost is the only way I can find that gets this to print +namespace boost { +template +std::ostream& operator<<(std::ostream& out, const optional& opt) { + if (opt) { + out << "Just " << *opt; + } else { + out << "Nothing"; + } + return out; +} +} template using const_opt_tuple = std::tuple...>; From a4f3c0f07ee94e4401baabe1cb0e06096e1491b8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 12:42:57 -0500 Subject: [PATCH 0833/1866] builds zip_longest test --- catchtest/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index 603ec080..5b333d41 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -41,6 +41,7 @@ progs = Split( takewhile unique_everseen unique_justseen + zip_longest ''' ) From bc80ff0028eee75f8485b50728ffc0fed697b734 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 12:44:09 -0500 Subject: [PATCH 0834/1866] removes include of iostream in zip_longest.hpp --- zip_longest.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/zip_longest.hpp b/zip_longest.hpp index 88886666..f6861458 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -4,7 +4,6 @@ #include "iterbase.hpp" #include -#include // TODO remove #include #include #include From 9687b5480c40677113def07bf669ed2a343bc1f8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 12:47:38 -0500 Subject: [PATCH 0835/1866] adds postfix ++ and == to zip_longest iters --- zip_longest.hpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/zip_longest.hpp b/zip_longest.hpp index f6861458..53d49e67 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -73,11 +73,21 @@ namespace iter { return *this; } + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + bool operator!=(const Iterator& other) const { return this->iter != other.iter || this->rest_iter != other.rest_iter; } + bool operator==(const Iterator& other) const { + return !(*this != other); + } + ZipIterDeref operator*() { if (this->iter != this->end) { return std::tuple_cat( @@ -147,10 +157,20 @@ namespace iter { return *this; } + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + bool operator!=(const Iterator& other) const { return this->iter != other.iter; } + bool operator==(const Iterator& other) const { + return !(*this != other); + } + std::tuple operator*() { if (this->iter != this->end) { return std::tuple{{*this->iter}}; From f8aa66a97710f6b92e7d7e5f6c7349f78eadd1d2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 12:55:01 -0500 Subject: [PATCH 0836/1866] tests that zip_longest'd elements can be modified --- catchtest/test_zip_longest.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/catchtest/test_zip_longest.cpp b/catchtest/test_zip_longest.cpp index 6a2afbc2..5431480c 100644 --- a/catchtest/test_zip_longest.cpp +++ b/catchtest/test_zip_longest.cpp @@ -92,3 +92,26 @@ TEST_CASE("zip longest: correctly detects longest at any position", REQUIRE( results == rc ); } } + +TEST_CASE("zip longest: when all are empty, terminates right away", + "[zip_longest]") { + const std::vector ivec{}; + const std::vector svec{}; + const std::string str{}; + + auto zl = zip_longest(ivec, svec, str); + REQUIRE( std::begin(zl) == std::end(zl) ); +} + +TEST_CASE("zip longest: can modify zipped sequences", "[zip_longest]") { + std::vector ns1 = {1, 2, 3}; + std::vector ns2 = {10, 11, 12}; + for (auto&& t : zip_longest(ns1, ns2)) { + *std::get<0>(t) = -1; + *std::get<1>(t) = -1; + } + + std::vector vc = {-1, -1, -1}; + REQUIRE( ns1 == vc ); + REQUIRE( ns2 == vc ); +} From e3639b38edefa2ad010cf3b1e473fa7bad4962e2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 13:21:29 -0500 Subject: [PATCH 0837/1866] specifies reversed array deref --- reversed.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reversed.hpp b/reversed.hpp index 7563b898..e62bf4dc 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -108,7 +108,7 @@ namespace iter { : sub_iter{iter} { } - auto operator*() -> decltype(*array) { + iterator_deref operator*() { return *(this->sub_iter - 1); } From 3679aaf5c0525581c21d5e8545c0449f2cc4c057 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 13:38:51 -0500 Subject: [PATCH 0838/1866] slice iter inherits from std iterator --- slice.hpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/slice.hpp b/slice.hpp index fa5f8e2a..76bfc88a 100644 --- a/slice.hpp +++ b/slice.hpp @@ -93,12 +93,15 @@ namespace iter { Slice(const Slice &) = default; - class Iterator { + class Iterator + : public std::iterator> + { private: iterator_type sub_iter; DifferenceType current; - const DifferenceType stop; - const DifferenceType step; + DifferenceType stop; + DifferenceType step; public: Iterator (iterator_type si, DifferenceType start, From 472b24ecdd48b70ef3f45f8647cdfed22ef1825b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 13:39:44 -0500 Subject: [PATCH 0839/1866] adds postfix ++ and == to slice iter --- slice.hpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/slice.hpp b/slice.hpp index 76bfc88a..859ae898 100644 --- a/slice.hpp +++ b/slice.hpp @@ -122,9 +122,19 @@ namespace iter { return *this; } + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + bool operator!=(const Iterator &) const { - return (this->step > 0 && this->current < this->stop)|| - (this->step < 0 && this->current > this->stop); + return (this->step > 0 && this->current < this->stop) + || (this->step < 0 && this->current > this->stop); + } + + bool operator==(const Iterator& other) const { + return !(*this != other); } }; From 626b08b91be9692c7d14965e5e246cbc0d7a4513 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 14:37:11 -0500 Subject: [PATCH 0840/1866] tests slice with just stop --- catchtest/test_slice.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 catchtest/test_slice.cpp diff --git a/catchtest/test_slice.cpp b/catchtest/test_slice.cpp new file mode 100644 index 00000000..c5f9a311 --- /dev/null +++ b/catchtest/test_slice.cpp @@ -0,0 +1,21 @@ +#include + +#include +#include +#include + +#include "helpers.hpp" +#include "catch.hpp" + +using iter::slice; +using Vec = const std::vector; + +TEST_CASE("slice: take from beginning", "[slice]") { + Vec ns = {10,11,12,13,14,15,16,17,18,19}; + auto sl = slice(ns, 5); + + Vec v(std::begin(sl), std::end(sl)); + Vec vc = {10,11,12,13,14}; + + REQUIRE( v == vc ); +} From b71c001ef12cba112af109de630cb6fc94db4137 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 14:37:38 -0500 Subject: [PATCH 0841/1866] builds slice test --- catchtest/SConstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index 5b333d41..cbf664c3 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -35,7 +35,7 @@ progs = Split( product repeat reversed - + slice sliding_window takewhile From d7d887097a930ebd50ebb40a7afe4743b7b8e54c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 14:41:03 -0500 Subject: [PATCH 0842/1866] tests slice with start and stop --- catchtest/test_slice.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/catchtest/test_slice.cpp b/catchtest/test_slice.cpp index c5f9a311..848f0cc3 100644 --- a/catchtest/test_slice.cpp +++ b/catchtest/test_slice.cpp @@ -19,3 +19,13 @@ TEST_CASE("slice: take from beginning", "[slice]") { REQUIRE( v == vc ); } + +TEST_CASE("slice: start and stop", "[slice]") { + Vec ns = {10,11,12,13,14,15,16,17,18,19}; + auto sl = slice(ns, 2, 6); + + Vec v(std::begin(sl), std::end(sl)); + Vec vc = {12, 13, 14, 15}; + + REQUIRE( v == vc ); +} From 492383c56fa23547983bc6ddc55fb9e33f83aba1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 14:41:29 -0500 Subject: [PATCH 0843/1866] adjusts include guards --- slice.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/slice.hpp b/slice.hpp index 859ae898..8621c1e6 100644 --- a/slice.hpp +++ b/slice.hpp @@ -1,5 +1,5 @@ -#ifndef SLICE_HPP -#define SLICE_HPP +#ifndef ITER_SLICE_HPP +#define ITER_SLICE_HPP #include "iterbase.hpp" @@ -179,4 +179,4 @@ namespace iter { } } -#endif //SLICE_HPP +#endif From b4a3d0a5a92c1caa214560c670ec7e894027df4c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 14:44:14 -0500 Subject: [PATCH 0844/1866] tests slice with step --- catchtest/test_slice.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/catchtest/test_slice.cpp b/catchtest/test_slice.cpp index 848f0cc3..96f5f9da 100644 --- a/catchtest/test_slice.cpp +++ b/catchtest/test_slice.cpp @@ -29,3 +29,13 @@ TEST_CASE("slice: start and stop", "[slice]") { REQUIRE( v == vc ); } + +TEST_CASE("slice: start, stop, step", "[slice]") { + Vec ns = {10,11,12,13,14,15,16,17,18,19}; + auto sl = slice(ns, 2, 8, 2); + + Vec v(std::begin(sl), std::end(sl)); + Vec vc = {12,14,16}; + + REQUIRE( v == vc ); +} From 26360638c550a8873ddae7bfb68b90fec5c6272a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 14:49:04 -0500 Subject: [PATCH 0845/1866] tests slice when stop is too high --- catchtest/test_slice.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/catchtest/test_slice.cpp b/catchtest/test_slice.cpp index 96f5f9da..9c860a8a 100644 --- a/catchtest/test_slice.cpp +++ b/catchtest/test_slice.cpp @@ -39,3 +39,11 @@ TEST_CASE("slice: start, stop, step", "[slice]") { REQUIRE( v == vc ); } + +TEST_CASE("slice: stop is beyond end of iterable", "[slice]") { + Vec ns = {1, 2, 3}; + auto sl = slice(ns, 10); + + Vec v(std::begin(sl), std::end(sl)); + REQUIRE( v == ns ); +} From f69b08fa4691da886feabf6f2f3e2b050abc80c7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 14:54:38 -0500 Subject: [PATCH 0846/1866] tests slice when start is too high --- catchtest/test_slice.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/catchtest/test_slice.cpp b/catchtest/test_slice.cpp index 9c860a8a..79d993a4 100644 --- a/catchtest/test_slice.cpp +++ b/catchtest/test_slice.cpp @@ -47,3 +47,9 @@ TEST_CASE("slice: stop is beyond end of iterable", "[slice]") { Vec v(std::begin(sl), std::end(sl)); REQUIRE( v == ns ); } + +TEST_CASE("slice: start is beyond end of iterable", "[slice]") { + Vec ns = {1, 2, 3}; + auto sl = slice(ns, 5, 10); + REQUIRE( std::begin(sl) == std::end(sl) ); +} From cc2c685797bd7174485bc6461fb961e71ee6689e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 15:00:12 -0500 Subject: [PATCH 0847/1866] tests slice with step going past stop --- catchtest/test_slice.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/catchtest/test_slice.cpp b/catchtest/test_slice.cpp index 79d993a4..d6845014 100644 --- a/catchtest/test_slice.cpp +++ b/catchtest/test_slice.cpp @@ -53,3 +53,12 @@ TEST_CASE("slice: start is beyond end of iterable", "[slice]") { auto sl = slice(ns, 5, 10); REQUIRE( std::begin(sl) == std::end(sl) ); } + +TEST_CASE("slice: (stop - start) % step != 0", "[slice]") { + Vec ns = {1, 2, 3, 4}; + auto sl = slice(ns, 0, 2, 3); + Vec v(std::begin(sl), std::end(sl)); + Vec vc = {1}; + + REQUIRE( v == vc ); +} From 29c73b012d5baaada12e104bd9e82b1a82a1b4f3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 15:07:29 -0500 Subject: [PATCH 0848/1866] tests slice with empty ranges --- catchtest/test_slice.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/catchtest/test_slice.cpp b/catchtest/test_slice.cpp index d6845014..4414276e 100644 --- a/catchtest/test_slice.cpp +++ b/catchtest/test_slice.cpp @@ -62,3 +62,15 @@ TEST_CASE("slice: (stop - start) % step != 0", "[slice]") { REQUIRE( v == vc ); } + +TEST_CASE("slice: invalid ranges give 0 size slices", "[slice]") { + Vec ns = {1, 2, 3}; + SECTION("stop > start, step < 0") { + auto sl = slice(ns, 1, 10,-1); + REQUIRE( std::begin(sl) == std::end(sl) ); + } + SECTION("stop < start, step > 0") { + auto sl = slice(ns, 2, 0, 3); + REQUIRE( std::begin(sl) == std::end(sl) ); + } +} From d7b1f8461df5960379e2409e69b5325d52d6f70c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 15:11:27 -0500 Subject: [PATCH 0849/1866] tests that slice doesn't move or copy elements --- catchtest/test_slice.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/catchtest/test_slice.cpp b/catchtest/test_slice.cpp index 4414276e..64093e4b 100644 --- a/catchtest/test_slice.cpp +++ b/catchtest/test_slice.cpp @@ -74,3 +74,13 @@ TEST_CASE("slice: invalid ranges give 0 size slices", "[slice]") { REQUIRE( std::begin(sl) == std::end(sl) ); } } + +// TODO test with BasicIterable can't currently be done because of +// range checking using std::distance. (also screws up infinite ranges) + +TEST_CASE("slice: with iterable doesn't move or copy elems", "[slice]") { + constexpr std::array arr{{{6}, {7}, {8}}}; + for (auto&& i : slice(arr, 2)) { + (void)i; + } +} From 1ba1a9bc96bc2c30b7a0d63db8725b0c840c22e6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 15:14:02 -0500 Subject: [PATCH 0850/1866] tests that zip_longest moves and binds correctly --- catchtest/test_zip_longest.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/catchtest/test_zip_longest.cpp b/catchtest/test_zip_longest.cpp index 5431480c..36d74dcb 100644 --- a/catchtest/test_zip_longest.cpp +++ b/catchtest/test_zip_longest.cpp @@ -115,3 +115,16 @@ TEST_CASE("zip longest: can modify zipped sequences", "[zip_longest]") { REQUIRE( ns1 == vc ); REQUIRE( ns2 == vc ); } + +TEST_CASE("zip_longest: binds to lvalues, moves rvalues", "[zip_longest]") { + itertest::BasicIterable b1{'x', 'y', 'z'}; + itertest::BasicIterable b2{'a', 'b'}; + SECTION("bind to first, moves second") { + zip_longest(b1, std::move(b2)); + } + SECTION("move first, bind to second") { + zip_longest(std::move(b2), b1); + } + REQUIRE_FALSE( b1.was_moved_from() ); + REQUIRE( b2.was_moved_from() ); +} From 29f0807e8f495a19ba242d87d231f0fd65a00127 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 15:15:44 -0500 Subject: [PATCH 0851/1866] tests zip_longest doesn't move or copy elements --- catchtest/test_zip_longest.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/catchtest/test_zip_longest.cpp b/catchtest/test_zip_longest.cpp index 36d74dcb..d6966e46 100644 --- a/catchtest/test_zip_longest.cpp +++ b/catchtest/test_zip_longest.cpp @@ -128,3 +128,10 @@ TEST_CASE("zip_longest: binds to lvalues, moves rvalues", "[zip_longest]") { REQUIRE_FALSE( b1.was_moved_from() ); REQUIRE( b2.was_moved_from() ); } + +TEST_CASE("zip_longest: doesn't move or copy elements", "[zip_longest]") { + constexpr itertest::SolidInt arr[] = {{6}, {7}, {8}}; + for (auto&& t : zip_longest(arr, arr)) { + (void)std::get<0>(t); + } +} From e65d114365a819230281ffe4ad7175276e3255dd Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 21:17:34 -0500 Subject: [PATCH 0852/1866] alphabetizes sconstruct --- catchtest/SConstruct | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index cbf664c3..f05eecea 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -15,8 +15,6 @@ env['ENV']['TERM'] = os.environ['TERM'] progs = Split( ''' - zip - range accumulate chain combinations @@ -33,6 +31,7 @@ progs = Split( permutations powerset product + range repeat reversed slice @@ -41,6 +40,7 @@ progs = Split( takewhile unique_everseen unique_justseen + zip zip_longest ''' ) From bbe4e09bca59ef40bf08f7903f12ef81ba410e01 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 21:23:36 -0500 Subject: [PATCH 0853/1866] uses empty base case zip_longest instead of specializing on one template parameter, specializes on 0 --- zip_longest.hpp | 74 ++++++++++++------------------------------------- 1 file changed, 18 insertions(+), 56 deletions(-) diff --git a/zip_longest.hpp b/zip_longest.hpp index 53d49e67..49114505 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -14,21 +14,21 @@ namespace iter { template using OptIterDeref = boost::optional>; - template + template class ZippedLongest; template ZippedLongest zip_longest(Containers&&...); template - class ZippedLongest { + class ZippedLongest { static_assert(!std::is_rvalue_reference::value, "Itertools cannot be templated with rvalue references"); friend ZippedLongest zip_longest( Container&&, RestContainers&&...); - template + template friend class ZippedLongest; private: @@ -115,78 +115,40 @@ namespace iter { }; - template - class ZippedLongest { - static_assert(!std::is_rvalue_reference::value, - "Itertools cannot be templated with rvalue references"); - - friend ZippedLongest zip_longest(Container&&); - - template - friend class ZippedLongest; - - private: - using OptType = OptIterDeref; - - Container container; - ZippedLongest(Container container) - : container(std::forward(container)) - { } - + template <> + class ZippedLongest<> { public: - class Iterator - : public std::iterator> + : public std::iterator> { - private: - iterator_type iter; - iterator_type end; public: - Iterator( - iterator_type it, - iterator_type in_end) - : iter{it}, - end{in_end} - { } - Iterator& operator++() { - if (this->iter != this->end) { - ++this->iter; - } return *this; } - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; + constexpr Iterator operator++(int) { + return *this; } - bool operator!=(const Iterator& other) const { - return this->iter != other.iter; + constexpr bool operator!=(const Iterator&) const { + return false; } - bool operator==(const Iterator& other) const { - return !(*this != other); + constexpr bool operator==(const Iterator&) const { + return true; } - std::tuple operator*() { - if (this->iter != this->end) { - return std::tuple{{*this->iter}}; - } - return std::tuple{{}}; + constexpr std::tuple<> operator*() { + return {}; } }; - Iterator begin() { - return {std::begin(this->container), - std::end(this->container)}; + constexpr Iterator begin() { + return {}; } - Iterator end() { - return {std::end(this->container), - std::end(this->container)}; + constexpr Iterator end() { + return {}; } }; From d243ac77cbe174b066e930f714b7a7fd8c5640dd Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 21:29:14 -0500 Subject: [PATCH 0854/1866] tests empty zip_longest() --- catchtest/test_zip_longest.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/catchtest/test_zip_longest.cpp b/catchtest/test_zip_longest.cpp index d6966e46..1e12a68a 100644 --- a/catchtest/test_zip_longest.cpp +++ b/catchtest/test_zip_longest.cpp @@ -116,6 +116,12 @@ TEST_CASE("zip longest: can modify zipped sequences", "[zip_longest]") { REQUIRE( ns2 == vc ); } +TEST_CASE("zip longest: empty zip_longest() is empty", "[zip_longest]") { + auto zl = zip_longest(); + REQUIRE( std::begin(zl) == std::end(zl) ); + REQUIRE_FALSE( std::begin(zl) != std::end(zl) ); +} + TEST_CASE("zip_longest: binds to lvalues, moves rvalues", "[zip_longest]") { itertest::BasicIterable b1{'x', 'y', 'z'}; itertest::BasicIterable b2{'a', 'b'}; From 7c30585260d33edf37caf0a78ae5e51408c9b394 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 21:37:38 -0500 Subject: [PATCH 0855/1866] removes wrap_iter, nothing uses it anymore --- wrap_iter.hpp | 51 --------------------------------------------------- 1 file changed, 51 deletions(-) delete mode 100644 wrap_iter.hpp diff --git a/wrap_iter.hpp b/wrap_iter.hpp deleted file mode 100644 index 70017b4b..00000000 --- a/wrap_iter.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef WRAP_ITER_HPP__ -#define WRAP_ITER_HPP__ - -#include - -namespace iter { - template - class wrap_iter { - private: - Iterator iter; - typename std::iterator_traits::difference_type step; - - public: - //using difference_type = typename std::iterator_traits::difference_type; - wrap_iter(const Iterator & iter, - typename std::iterator_traits::difference_type step) : - iter(iter), - step(step) - { } - - wrap_iter & operator++() { - std::advance(iter,step); - return *this; - } - - bool operator!=(const wrap_iter & rhs) const { - return this->iter != rhs.iter; - } - - auto operator*() const -> decltype(*iter) - { - return *iter; - } - }; - - template - wrap_iter make_wrap_iter(const Iterator & iter, - typename std::iterator_traits::difference_type step) { - return wrap_iter(iter,step); - } - -} -namespace std { -template - struct iterator_traits> { - using difference_type = typename iterator_traits::difference_type; - using iterator_category = typename iterator_traits::iterator_category; - //should add the rest later for a more usable class - }; -} -#endif //WRAP_ITER_HPP__ From e96bfe7dffef436150c4b0b9da42204815689eef Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 21:40:36 -0500 Subject: [PATCH 0856/1866] removes extra move, makes iterator assignable --- accumulate.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index 218c98cb..8df2e409 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -46,7 +46,7 @@ namespace iter { std::is_default_constructible::value, "Cannot accumulate a non-default constructible type"); - Accumulator(Container container, AccumulateFunc accumulate_func) + Accumulator(Container&& container, AccumulateFunc accumulate_func) : container(std::forward(container)), accumulate_func(accumulate_func) { } @@ -57,7 +57,7 @@ namespace iter { { private: iterator_type sub_iter; - const iterator_type sub_end; + iterator_type sub_end; AccumulateFunc accumulate_func; AccumVal acc_val; public: @@ -150,4 +150,4 @@ namespace iter { } -#endif //ifndef ITER_ACCUMULATE_H_ +#endif From 2a9488a27bc34f253c350b8430ca4ce98883a959 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 21:45:16 -0500 Subject: [PATCH 0857/1866] eliminates extra moves --- chain.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/chain.hpp b/chain.hpp index 399ea3e9..5130dc56 100644 --- a/chain.hpp +++ b/chain.hpp @@ -30,7 +30,7 @@ namespace iter { private: Container container; Chained rest_chained; - Chained(Container container, RestContainers&&... rest) + Chained(Container&& container, RestContainers&&... rest) : container(std::forward(container)), rest_chained{std::forward(rest)...} { } @@ -45,7 +45,7 @@ namespace iter { using RestIter = typename Chained::Iterator; iterator_type sub_iter; - const iterator_type sub_end; + iterator_type sub_end; RestIter rest_iter; bool at_end; @@ -112,7 +112,7 @@ namespace iter { private: Container container; - Chained(Container container) + Chained(Container&& container) : container(std::forward(container)) { } @@ -124,7 +124,7 @@ namespace iter { { private: iterator_type sub_iter; - const iterator_type sub_end; + iterator_type sub_end; public: Iterator(const iterator_type& s_begin, @@ -173,7 +173,7 @@ namespace iter { private: Container container; friend class ChainMaker; - ChainedFromIterable(Container container) + ChainedFromIterable(Container&& container) : container(std::forward(container)) { } @@ -315,4 +315,4 @@ namespace iter { } -#endif // #ifndef ITER_CHAIN_HPP_ +#endif From 8c02af2468b80fdad17b11aad27deeaffca10366 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 21:46:46 -0500 Subject: [PATCH 0858/1866] eliminates extra moves --- combinations.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/combinations.hpp b/combinations.hpp index 089d0abc..d98ecd6e 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -30,7 +30,7 @@ namespace iter { friend Combinator> combinations( std::initializer_list, std::size_t); - Combinator(Container in_container, std::size_t in_length) + Combinator(Container&& in_container, std::size_t in_length) : container(std::forward(in_container)), length{in_length} { } From 1283d231d38881cdd6bdd16e46df5e40cdb950df Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 21:48:36 -0500 Subject: [PATCH 0859/1866] eliminates extra moves --- 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 4b521e76..2ed2af4b 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -36,7 +36,7 @@ namespace iter { combinations_with_replacement( std::initializer_list, std::size_t); - CombinatorWithReplacement(Container container, std::size_t n) + CombinatorWithReplacement(Container&& container, std::size_t n) : container(std::forward(container)), length{n} { } From 0779083e8eb4bd5bcf33987fedf429f85b0a66f3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 21:52:23 -0500 Subject: [PATCH 0860/1866] removes moves, makes iterators assignable --- compress.hpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/compress.hpp b/compress.hpp index 9d3ff7d0..4dfab7a8 100644 --- a/compress.hpp +++ b/compress.hpp @@ -48,7 +48,8 @@ namespace iter { Con&&, std::initializer_list); template - friend Compressed, std::initializer_list> compress( + friend Compressed, + std::initializer_list> compress( std::initializer_list, std::initializer_list); @@ -56,7 +57,7 @@ namespace iter { using selector_iter_type = decltype(std::begin(selectors)); // Value constructor for use only in the compress function - Compressed(Container container, Selector selectors) + Compressed(Container&& container, Selector&& selectors) : container(std::forward(container)), selectors(std::forward(selectors)) { } @@ -69,10 +70,10 @@ namespace iter { { private: iterator_type sub_iter; - const iterator_type sub_end; + iterator_type sub_end; selector_iter_type selector_iter; - const selector_iter_type selector_end; + selector_iter_type selector_end; void increment_iterators() { ++this->sub_iter; @@ -80,9 +81,9 @@ namespace iter { } void skip_failures() { - while (this->sub_iter != this->sub_end && - this->selector_iter != this->selector_end && - !*this->selector_iter) { + while (this->sub_iter != this->sub_end + && this->selector_iter != this->selector_end + && !*this->selector_iter) { this->increment_iterators(); } } @@ -100,7 +101,7 @@ namespace iter { this->skip_failures(); } - iterator_deref operator*() const { + iterator_deref operator*() { return *this->sub_iter; } @@ -117,8 +118,8 @@ namespace iter { } bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter && - this->selector_iter != other.selector_iter; + return this->sub_iter != other.sub_iter + && this->selector_iter != other.selector_iter; } bool operator==(const Iterator& other) const { From d760457c3d2df903008f22b5bfde11c61c67d973 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 21:59:14 -0500 Subject: [PATCH 0861/1866] eliminates extra moves --- cycle.hpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/cycle.hpp b/cycle.hpp index 8c8962e1..484fc922 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -9,7 +9,6 @@ namespace iter { - //Forward declarations of Cycle and cycle template class Cycle; @@ -22,7 +21,6 @@ namespace iter { template class Cycle { private: - // The cycle function is the only thing allowed to create a Cycle friend Cycle cycle(Container&&); template friend Cycle> cycle( @@ -30,8 +28,7 @@ namespace iter { Container container; - // Value constructor for use only in the cycle function - Cycle(Container container) + Cycle(Container&& container) : container(std::forward(container)) { } @@ -53,7 +50,7 @@ namespace iter { end{end} { } - iterator_deref operator*() const { + iterator_deref operator*() { return *this->sub_iter; } @@ -93,7 +90,6 @@ namespace iter { }; - // Helper function to instantiate a Cycle template Cycle cycle(Container&& container) { return {std::forward(container)}; From 70334e769c44af08bcd1b0b67e75ebb04a12bb73 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 22:01:01 -0500 Subject: [PATCH 0862/1866] eliminates extra moves --- dropwhile.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index 0f2725cd..169aa305 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -32,7 +32,7 @@ namespace iter { friend DropWhile> dropwhile( FF, std::initializer_list); - DropWhile(FilterFunc filter_func, Container container) + DropWhile(FilterFunc filter_func, Container&& container) : container(std::forward(container)), filter_func(filter_func) { } @@ -44,7 +44,7 @@ namespace iter { { private: iterator_type sub_iter; - const iterator_type sub_end; + iterator_type sub_end; FilterFunc filter_func; // skip all values for which the predicate is true @@ -66,7 +66,7 @@ namespace iter { this->skip_passes(); } - iterator_deref operator*() const { + iterator_deref operator*() { return *this->sub_iter; } From b7f55d2e5706d76f6c7b587a4036ef62608a2b72 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 22:08:00 -0500 Subject: [PATCH 0863/1866] eliminates extra moves --- enumerate.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 845b0412..cba785f5 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -47,7 +47,7 @@ namespace iter { using BasePair = std::pair>; // Value constructor for use only in the enumerate function - Enumerable(Container container) + Enumerable(Container&& container) : container(std::forward(container)) { } @@ -71,7 +71,7 @@ namespace iter { iterator_type sub_iter; std::size_t index; public: - Iterator (iterator_type si) + Iterator(const iterator_type& si) : sub_iter{si}, index{0} { } @@ -121,8 +121,8 @@ namespace iter { Enumerable> enumerate( std::initializer_list il) { - return {il}; + return {std::move(il)}; } } -#endif //#ifndef ITER_ENUMERATE_H_ +#endif From 9c30253adb51e4ae435814fab83862bf94897ad8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 22:11:28 -0500 Subject: [PATCH 0864/1866] corrects handling of init lists --- combinations.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/combinations.hpp b/combinations.hpp index d98ecd6e..c7c36724 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -151,7 +151,7 @@ namespace iter { template Combinator> combinations( std::initializer_list il, std::size_t length) { - return {il, length}; + return {std::move(il), length}; } } #endif From 2140cbbdc701a284e704604d30f7518245afb912 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 22:12:02 -0500 Subject: [PATCH 0865/1866] corrects handling of init lasts --- 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 2ed2af4b..62e24db8 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -135,7 +135,7 @@ namespace iter { CombinatorWithReplacement> combinations_with_replacement( std::initializer_list il, std::size_t length) { - return {il, length}; + return {std::move(il), length}; } } From 66ad83ff1fed6088c9fbf11b46dff64a618883b5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 22:17:56 -0500 Subject: [PATCH 0866/1866] eliminates extra moves --- filter.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/filter.hpp b/filter.hpp index 28ab60b7..fdefe612 100644 --- a/filter.hpp +++ b/filter.hpp @@ -35,7 +35,7 @@ namespace iter { FF, std::initializer_list); // Value constructor for use only in the filter function - Filter(FilterFunc filter_func, Container container) + Filter(FilterFunc filter_func, Container&& container) : container(std::forward(container)), filter_func(filter_func) { } From 02dfbf447f4084802f1c710247ab5273637d414f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 22:21:39 -0500 Subject: [PATCH 0867/1866] corrects include guards --- filterfalse.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/filterfalse.hpp b/filterfalse.hpp index 38ded919..3bad5fa0 100644 --- a/filterfalse.hpp +++ b/filterfalse.hpp @@ -1,5 +1,5 @@ -#ifndef FILTER_FALSE__HPP__ -#define FILTER_FALSE__HPP__ +#ifndef ITER_FILTER_FALSE_HPP_ +#define ITER_FILTER_FALSE_HPP_ #include "iterbase.hpp" #include "filter.hpp" @@ -102,4 +102,4 @@ namespace iter { } } -#endif //#ifndef FILTER_FALSE__HPP__ +#endif From 30afc6c961ea48a8db75238b92b7098d04d44ea8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 22:23:14 -0500 Subject: [PATCH 0868/1866] corrects include guards --- groupby.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index 9ac0bfb1..d0e8cbf5 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -1,5 +1,5 @@ -#ifndef GROUP__BY__HPP -#define GROUP__BY__HPP +#ifndef ITER_GROUP_BY_HPP_ +#define ITER_GROUP_BY_HPP_ #include "iterbase.hpp" @@ -294,4 +294,4 @@ namespace iter { } -#endif //#ifndef GROUP__BY__HPP +#endif From d705b1d0118e73e499d8af83709e043edb1ea0c7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 22:24:59 -0500 Subject: [PATCH 0869/1866] eliminates extra moves --- groupby.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index d0e8cbf5..718b4abc 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -35,7 +35,7 @@ namespace iter { decltype(std::declval()( std::declval>())); - GroupBy(Container container, KeyFunc key_func) + GroupBy(Container&& container, KeyFunc key_func) : container(std::forward(container)), key_func(key_func) { } @@ -62,7 +62,7 @@ namespace iter { private: iterator_type sub_iter; iterator_type sub_iter_peek; - const iterator_type sub_end; + iterator_type sub_end; KeyFunc key_func; public: From e0bd55e342bd2ce3bde607bf1ac973f8922acb8f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 22:28:59 -0500 Subject: [PATCH 0870/1866] eliminates extra moves --- grouper.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/grouper.hpp b/grouper.hpp index af75ade3..4fdcfec7 100644 --- a/grouper.hpp +++ b/grouper.hpp @@ -1,5 +1,5 @@ -#ifndef GROUPER_HPP_ -#define GROUPER_HPP_ +#ifndef ITER_GROUPER_HPP_ +#define ITER_GROUPER_HPP_ #include "iterbase.hpp" @@ -28,7 +28,7 @@ namespace iter { Container container; std::size_t group_size; - Grouper(Container c, std::size_t sz) + Grouper(Container&& c, std::size_t sz) : container(std::forward(c)), group_size{sz} { } @@ -127,7 +127,7 @@ namespace iter { template Grouper> grouper( std::initializer_list il, std::size_t group_size) { - return {il, group_size}; + return {std::move(il), group_size}; } } -#endif // #ifndef GROUPER_HPP_ +#endif From 2134a12cdcd9c92b9eccafb95c91843094bbc91b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 22:32:11 -0500 Subject: [PATCH 0871/1866] eliminates extra moves --- permutations.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/permutations.hpp b/permutations.hpp index bb383ac7..97ae6639 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -19,7 +19,7 @@ namespace iter { std::vector>; public: - Permuter(Container in_container) + Permuter(Container&& in_container) : container(std::forward(in_container)) { } @@ -88,7 +88,7 @@ namespace iter { template Permuter> permutations( std::initializer_list il) { - return {il}; + return {std::move(il)}; } } From 1aab55db8d84aee86a093bfd8952f7bb2caa5fcb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 22:33:35 -0500 Subject: [PATCH 0872/1866] eliminates extra moves --- powerset.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/powerset.hpp b/powerset.hpp index 69abf4fa..964b0651 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -20,7 +20,7 @@ namespace iter { decltype(combinations(std::declval(), 0)); public: - Powersetter(Container in_container) + Powersetter(Container&& in_container) : container(std::forward(in_container)) { } @@ -92,7 +92,7 @@ namespace iter { template Powersetter> powerset( std::initializer_list il) { - return {il}; + return {std::move(il)}; } } #endif From 428679911cfb73926d477b946f718e92198ab6c4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 22:35:35 -0500 Subject: [PATCH 0873/1866] eliminates extra moves --- product.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/product.hpp b/product.hpp index c40909f8..6d7d281d 100644 --- a/product.hpp +++ b/product.hpp @@ -33,7 +33,7 @@ namespace iter { private: Container container; Productor rest_products; - Productor(Container container, RestContainers&&... rest) + Productor(Container&& container, RestContainers&&... rest) : container(std::forward(container)), rest_products{std::forward(rest)...} { } From fbbaafc138790e48257d61dfe8f0b392ebef6839 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 22:36:05 -0500 Subject: [PATCH 0874/1866] eliminates extra moves --- product.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/product.hpp b/product.hpp index 6d7d281d..92e0c5b8 100644 --- a/product.hpp +++ b/product.hpp @@ -83,8 +83,8 @@ namespace iter { bool operator!=(const Iterator& other) const { return this->iter != other.iter && - (RestIter::is_base_iter || - this->rest_iter != other.rest_iter); + (RestIter::is_base_iter + || this->rest_iter != other.rest_iter); } bool operator==(const Iterator& other) const { From 124d93834b7e7fda05f867415230a0b50a287120 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 22:38:31 -0500 Subject: [PATCH 0875/1866] eliminates extra moves --- reversed.hpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/reversed.hpp b/reversed.hpp index e62bf4dc..13f0689b 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -20,14 +20,11 @@ namespace iter { Container container; friend Reverser reversed(Container&&); - Reverser(Container container) + Reverser(Container&& container) : container(std::forward(container)) { } - Reverser() = delete; - Reverser& operator=(const Reverser&) = delete; public: - Reverser(const Reverser&) = default; class Iterator : public std::iterator< std::input_iterator_tag, iterator_traits_deref> @@ -94,8 +91,6 @@ namespace iter { Reverser(T *array) : array{array} { } - Reverser() = delete; - Reverser& operator=(const Reverser&) = delete; public: Reverser(const Reverser&) = default; From e1d653d6fd600e50b33cd3c2b7b1aae27571abe0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 22:39:08 -0500 Subject: [PATCH 0876/1866] eliminates extra moves --- reversed.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reversed.hpp b/reversed.hpp index 13f0689b..9d580ec5 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -144,4 +144,4 @@ namespace iter { } -#endif //ITER_REVERSE_HPP_ +#endif From e6b7042b86c1106f76ed40f042f6bcb7c635b784 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 22:45:10 -0500 Subject: [PATCH 0877/1866] eliminates extra moves --- slice.hpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/slice.hpp b/slice.hpp index 8621c1e6..be0d5ac2 100644 --- a/slice.hpp +++ b/slice.hpp @@ -1,5 +1,5 @@ -#ifndef ITER_SLICE_HPP -#define ITER_SLICE_HPP +#ifndef ITER_SLICE_HPP_ +#define ITER_SLICE_HPP_ #include "iterbase.hpp" @@ -65,7 +65,7 @@ namespace iter { //template //friend Slice> slice(std::initializer_list); public: - Slice(Container in_container, DifferenceType start, + Slice(Container&& in_container, DifferenceType start, DifferenceType stop, DifferenceType step) : container(std::forward(in_container)), start{start}, @@ -87,11 +87,6 @@ namespace iter { } } - Slice() = delete; - Slice& operator=(const Slice&) = delete; - - Slice(const Slice &) = default; - class Iterator : public std::iterator operator*() const { + iterator_deref operator*() { return *this->sub_iter; } @@ -169,13 +164,13 @@ namespace iter { Slice, DifferenceType> slice( std::initializer_list il, DifferenceType start, DifferenceType stop, DifferenceType step=1) { - return {il, start, stop, step}; + return {std::move(il), start, stop, step}; } template Slice, DifferenceType> slice( std::initializer_list il, DifferenceType stop) { - return {il, 0, stop, 1}; + return {std::move(il), 0, stop, 1}; } } From 232dcae035ee0049edce2f777ad0ff0b8b5da344 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 22:47:43 -0500 Subject: [PATCH 0878/1866] eliminates extra moves --- sliding_window.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sliding_window.hpp b/sliding_window.hpp index 48d4ca1c..4efdf7d1 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -30,7 +30,7 @@ namespace iter { friend SlidingWindow> sliding_window( std::initializer_list, std::size_t); - SlidingWindow(Container container, std::size_t win_sz) + SlidingWindow(Container&& container, std::size_t win_sz) : container(std::forward(container)), window_size{win_sz} { } @@ -110,7 +110,7 @@ namespace iter { template SlidingWindow> sliding_window( std::initializer_list il, std::size_t window_size) { - return {il, window_size}; + return {std::move(il), window_size}; } } From 4a732c156bed3bb4ee90a2d5b5b09b87a670f0f7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 22:49:41 -0500 Subject: [PATCH 0879/1866] eliminates extra moves --- sorted.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sorted.hpp b/sorted.hpp index 349fc881..05c5a3e3 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -1,5 +1,5 @@ -#ifndef SORTED__HPP__ -#define SORTED__HPP__ +#ifndef ITER_SORTED_HPP_ +#define ITER_SORTED_HPP_ #include "iterbase.hpp" @@ -29,7 +29,7 @@ namespace iter { Sorted() = delete; Sorted& operator=(const Sorted&) = delete; - Sorted(Container in_container, CompareFunc compare_func) + Sorted(Container&& in_container, CompareFunc compare_func) : container(std::forward(in_container)) { // Fill the sorted_iters vector with an iterator to each @@ -93,4 +93,4 @@ namespace iter { } -#endif //#ifndef SORTED__HPP__ +#endif From b192188b5a533bb04a88a9c2ca6c85edd02ae556 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 22:50:40 -0500 Subject: [PATCH 0880/1866] eliminates extra moves --- takewhile.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/takewhile.hpp b/takewhile.hpp index de5c7178..12eb4368 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -33,7 +33,7 @@ namespace iter { friend TakeWhile> takewhile( FF, std::initializer_list); - TakeWhile(FilterFunc filter_func, Container container) + TakeWhile(FilterFunc filter_func, Container&& container) : container(std::forward(container)), filter_func(filter_func) { } From 323774171f2c9a8dcda4e5bf33eec7b791777ab6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 22:51:09 -0500 Subject: [PATCH 0881/1866] eliminates extra moves --- zip.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zip.hpp b/zip.hpp index a77061bf..64b3f087 100644 --- a/zip.hpp +++ b/zip.hpp @@ -31,7 +31,7 @@ namespace iter { private: Container container; Zipped rest_zipped; - Zipped(Container container, RestContainers&&... rest) + Zipped(Container&& container, RestContainers&&... rest) : container(std::forward(container)), rest_zipped{std::forward(rest)...} { } @@ -154,4 +154,4 @@ namespace iter { } } -#endif // #ifndef ITER_ZIP_HPP_ +#endif From 436d5d0bdf0ddacd69eff84e1583b96bde47cfa4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Jan 2015 22:53:37 -0500 Subject: [PATCH 0882/1866] eliminates extra moves --- zip_longest.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zip_longest.hpp b/zip_longest.hpp index 49114505..cc6705b9 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -38,7 +38,7 @@ namespace iter { Container container; ZippedLongest rest_zipped; - ZippedLongest(Container container, RestContainers&&... rest) + ZippedLongest(Container&& container, RestContainers&&... rest) : container(std::forward(container)), rest_zipped{std::forward(rest)...} { } From 1199eeb08d7fe6bbaa0b0f3590bdd5ae6eff0217 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 28 Jan 2015 16:26:22 -0500 Subject: [PATCH 0883/1866] adds TMP for advancing O(1) when possible --- iterbase.hpp | 113 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 72 insertions(+), 41 deletions(-) diff --git a/iterbase.hpp b/iterbase.hpp index d426af91..81f6ff95 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -15,46 +15,6 @@ #include namespace iter { - // because std::advance assumes a lot and is actually smart, I need a dumb - // version that will work with most things - template - void dumb_advance(InputIt& iter, Distance distance=1) { - for (Distance i(0); i < distance; ++i) { - ++iter; - } - } - - // iter will not be incremented past end - template - void dumb_advance(InputIt& iter, const InputIt& end, Distance distance=1) { - for (Distance i(0); i < distance && iter != end; ++i) { - ++iter; - } - } - - template - ForwardIt dumb_next(ForwardIt it, Distance distance=1) { - dumb_advance(it, distance); - return it; - } - - template - ForwardIt dumb_next( - ForwardIt it, const ForwardIt& end, Distance distance=1) { - dumb_advance(it, end, distance); - return it; - } - - template - Distance dumb_size(Container&& container) { - Distance d{0}; - for (auto it = std::begin(container), end = std::end(container); - it != end; - ++it) { - ++d; - } - return d; - } // iterator_type is the type of C's iterator template @@ -95,6 +55,77 @@ namespace iter { typename std::remove_const< iterator_deref>::type>::type; + template + struct is_random_access_iter : std::false_type { }; + + template + struct is_random_access_iter::iterator_category, + std::random_access_iterator_tag>::value, + void>::type> : std::true_type { }; + + template + using has_random_access_iter = is_random_access_iter>; + // because std::advance assumes a lot and is actually smart, I need a dumb + + // version that will work with most things + template + void dumb_advance(InputIt& iter, Distance distance=1) { + for (Distance i(0); i < distance; ++i) { + ++iter; + } + } + + template + void dumb_advance_impl(Iter& iter, const Iter& end, + Distance distance, std::false_type) { + for (Distance i(0); i < distance && iter != end; ++i) { + ++iter; + } + } + + template + void dumb_advance_impl(Iter& iter, const Iter& end, + Distance distance, std::true_type) { + if (static_cast(end - iter) < distance) { + iter = end; + } else { + iter += distance; + } + } + + // iter will not be incremented past end + template + void dumb_advance(Iter& iter, const Iter& end, Distance distance=1) { + dumb_advance_impl(iter, end, distance, is_random_access_iter{}); + } + + template + ForwardIt dumb_next(ForwardIt it, Distance distance=1) { + dumb_advance(it, distance); + return it; + } + + template + ForwardIt dumb_next( + ForwardIt it, const ForwardIt& end, Distance distance=1) { + dumb_advance(it, end, distance); + return it; + } + + template + Distance dumb_size(Container&& container) { + Distance d{0}; + for (auto it = std::begin(container), end = std::end(container); + it != end; + ++it) { + ++d; + } + return d; + } + template struct are_same : std::true_type { }; @@ -105,4 +136,4 @@ namespace iter { std::is_same::value && are_same::value> { }; } -#endif // #ifndef ITERBASE_HPP_ +#endif From 6b74744e402555ed4257432ea8ce069fc0249bab Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 28 Jan 2015 16:29:29 -0500 Subject: [PATCH 0884/1866] tests that slice moves and binds correctly --- catchtest/test_slice.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/catchtest/test_slice.cpp b/catchtest/test_slice.cpp index 64093e4b..d7992dee 100644 --- a/catchtest/test_slice.cpp +++ b/catchtest/test_slice.cpp @@ -65,18 +65,29 @@ TEST_CASE("slice: (stop - start) % step != 0", "[slice]") { TEST_CASE("slice: invalid ranges give 0 size slices", "[slice]") { Vec ns = {1, 2, 3}; - SECTION("stop > start, step < 0") { - auto sl = slice(ns, 1, 10,-1); + SECTION("negative step") { + auto sl = slice(ns, 1, 10, -1); REQUIRE( std::begin(sl) == std::end(sl) ); } - SECTION("stop < start, step > 0") { + SECTION("stop < start") { auto sl = slice(ns, 2, 0, 3); REQUIRE( std::begin(sl) == std::end(sl) ); } } -// TODO test with BasicIterable can't currently be done because of -// range checking using std::distance. (also screws up infinite ranges) +TEST_CASE("slice: moves rvalues and binds to lvalues", "[slice]") { + itertest::BasicIterable bi{1, 2, 3, 4}; + slice(bi, 1, 3); + REQUIRE_FALSE( bi.was_moved_from() ); + auto sl = slice(std::move(bi), 1, 3); + REQUIRE( bi.was_moved_from() ); + + Vec v(std::begin(sl), std::end(sl)); + Vec vc = {2, 3}; + + REQUIRE( v == vc ); +} + TEST_CASE("slice: with iterable doesn't move or copy elems", "[slice]") { constexpr std::array arr{{{6}, {7}, {8}}}; From b821337de75ed93131d065e86e2dd1c7b5f10725 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 28 Jan 2015 16:30:21 -0500 Subject: [PATCH 0885/1866] removes slice SFINAE, doesn't calculate distance --- slice.hpp | 78 +++++++++++++++---------------------------------------- 1 file changed, 21 insertions(+), 57 deletions(-) diff --git a/slice.hpp b/slice.hpp index be0d5ac2..d04f863b 100644 --- a/slice.hpp +++ b/slice.hpp @@ -19,38 +19,6 @@ namespace iter { //template //Slice slice(Container &&); - template - class has_size - { - typedef char one; - typedef long two; - - template static one test( decltype(&C::size) ) ; - template static two test(...); - - - public: - enum { value = sizeof(test(0)) == sizeof(char) }; - }; - template - typename std::enable_if::value, std::size_t>::type - size(const Container& container) { - return container.size(); - } - - template - typename std::enable_if::value, std::size_t>::type - size(const Container& container) { - return std::distance(std::begin(container), std::end(container)); - } - - template - std::size_t size(const T (&)[N]) { - return N; - } - - - template class Slice { private: @@ -68,24 +36,10 @@ namespace iter { Slice(Container&& in_container, DifferenceType start, DifferenceType stop, DifferenceType step) : container(std::forward(in_container)), - start{start}, + start{start < stop && step > 0 ? start : stop}, stop{stop}, step{step} - { - // sets stop = start if the range is empty - if ((start < stop && step <=0) || - (start > stop && step >=0)){ - this->stop = start; - } - if (this->stop > static_cast( - size(this->container))) { - this->stop = static_cast(size( - this->container)); - } - if (this->start < 0) { - this->start = 0; - } - } + { } class Iterator @@ -94,14 +48,19 @@ namespace iter { { private: iterator_type sub_iter; + iterator_type sub_end; DifferenceType current; DifferenceType stop; DifferenceType step; public: - Iterator (iterator_type si, DifferenceType start, - DifferenceType stop, DifferenceType step) - : sub_iter{si}, + Iterator (iterator_type si, + iterator_type se, + DifferenceType start, + DifferenceType stop, + DifferenceType step) + : sub_iter{std::move(si)}, + sub_end{std::move(se)}, current{start}, stop{stop}, step{step} @@ -112,8 +71,11 @@ namespace iter { } Iterator& operator++() { - std::advance(this->sub_iter, this->step); + dumb_advance(this->sub_iter, this->sub_end,this->step); this->current += this->step; + if (this->stop < this->current ) { + this->current = this->stop; + } return *this; } @@ -123,9 +85,9 @@ namespace iter { return ret; } - bool operator!=(const Iterator &) const { - return (this->step > 0 && this->current < this->stop) - || (this->step < 0 && this->current > this->stop); + bool operator!=(const Iterator& other) const { + return this->sub_iter != other.sub_iter + && this->current != other.current; } bool operator==(const Iterator& other) const { @@ -134,12 +96,14 @@ namespace iter { }; Iterator begin() { - return {std::next(std::begin(this->container), this->start), + auto it = std::begin(this->container); + dumb_advance(it, std::end(this->container), this->start); + return {std::move(it), std::end(this->container), this->start, this->stop, this->step}; } Iterator end() { - return {std::next(std::begin(this->container), this->stop), + return {std::end(this->container), std::end(this->container), this->stop, this->stop, this->step}; } From 9e740f41d2cf4c6f518bf2ffb8ef14059a59fe69 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 28 Jan 2015 16:35:38 -0500 Subject: [PATCH 0886/1866] tests slice with empty sequence --- catchtest/test_slice.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/catchtest/test_slice.cpp b/catchtest/test_slice.cpp index d7992dee..3d95380e 100644 --- a/catchtest/test_slice.cpp +++ b/catchtest/test_slice.cpp @@ -40,6 +40,12 @@ TEST_CASE("slice: start, stop, step", "[slice]") { REQUIRE( v == vc ); } +TEST_CASE("slice: empty iterable", "[slice]") { + Vec ns{}; + auto sl = slice(ns, 3); + REQUIRE( std::begin(sl) == std::end(sl) ); +} + TEST_CASE("slice: stop is beyond end of iterable", "[slice]") { Vec ns = {1, 2, 3}; auto sl = slice(ns, 10); From b96ef0b1dc89e1630b99a23303fc7845573eebf0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 28 Jan 2015 17:12:34 -0500 Subject: [PATCH 0887/1866] uses vector instead of set so it's printable --- catchtest/test_combinations.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/catchtest/test_combinations.cpp b/catchtest/test_combinations.cpp index c366cdba..a3149edf 100644 --- a/catchtest/test_combinations.cpp +++ b/catchtest/test_combinations.cpp @@ -12,14 +12,13 @@ using iter::combinations; using itertest::BasicIterable; using itertest::SolidInt; -using CharCombSet = std::multiset>; +using CharCombSet = std::vector>; TEST_CASE("combinations: Simple combination of 4", "[combinations]") { std::string s{"ABCD"}; CharCombSet sc; for (auto v : combinations(s, 2)) { - std::vector vcopy(std::begin(v), std::end(v)); - sc.insert(vcopy); + sc.emplace_back(std::begin(v), std::end(v)); } CharCombSet ans = From 20c44c151cb5363431a2308696f06ea6c7d31ea5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 28 Jan 2015 17:27:52 -0500 Subject: [PATCH 0888/1866] tests that comb iters compare for real --- catchtest/test_combinations.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/catchtest/test_combinations.cpp b/catchtest/test_combinations.cpp index a3149edf..e5c015df 100644 --- a/catchtest/test_combinations.cpp +++ b/catchtest/test_combinations.cpp @@ -26,6 +26,17 @@ TEST_CASE("combinations: Simple combination of 4", "[combinations]") { REQUIRE( ans == sc ); } +TEST_CASE("combinations: iterators can be compared", "[combinations]") { + std::string s{"ABCD"}; + auto c = combinations(s, 2); + auto it = std::begin(c); + REQUIRE( it == std::begin(c) ); + REQUIRE_FALSE( it != std::begin(c) ); + ++it; + REQUIRE( it != std::begin(c) ); + REQUIRE_FALSE( it == std::begin(c) ); +} + TEST_CASE("combinations: size too large gives no results", "[combinations]") { std::string s{"ABCD"}; auto c = combinations(s, 5); From e467b37506c273a285eeae175f93ef79adafc4d1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 28 Jan 2015 17:28:30 -0500 Subject: [PATCH 0889/1866] lets comb iters compare for real --- combinations.hpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/combinations.hpp b/combinations.hpp index c7c36724..ecacfa35 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -45,7 +45,8 @@ namespace iter { private: typename std::remove_reference::type *container_p; std::vector> indicies; - bool not_done = true; + int steps = 0; + bool done = false; public: Iterator(Container& in_container, std::size_t n) @@ -53,7 +54,8 @@ namespace iter { indicies{n} { if (n == 0) { - not_done = false; + this->done = true; + this->steps = -1; return; } size_t inc = 0; @@ -64,7 +66,7 @@ namespace iter { iter = it; ++inc; } else { - not_done = false; + done = true; break; } } @@ -102,7 +104,7 @@ namespace iter { ++inc; } } else { - not_done = false; + done = true; break; } } else { @@ -111,6 +113,7 @@ namespace iter { //we break because none of the rest of the items need //to be incremented } + ++this->steps; return *this; } @@ -120,16 +123,13 @@ namespace iter { return ret; } - bool operator!=(const Iterator&) const { - //because of the way this is done you have to start from - //the begining of the range and end at the end, you could - //break in the middle of the loop though, it's not - //different from the way that python's works - return not_done; + bool operator!=(const Iterator& other) const { + return !(*this == other); } bool operator==(const Iterator& other) const { - return !(*this != other); + return (this->done && (this->done == other.done)) + || this->steps == other.steps; } }; @@ -138,7 +138,7 @@ namespace iter { } Iterator end() { - return {this->container, this->length}; + return {this->container, 0}; } }; From c3c9d1d029a0d274b5747eedb0912339c5a79f78 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 28 Jan 2015 17:39:50 -0500 Subject: [PATCH 0890/1866] removes `done` datamember from Combinator just uses the `steps` to figure out when it's done --- combinations.hpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/combinations.hpp b/combinations.hpp index ecacfa35..18475099 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -43,10 +43,14 @@ namespace iter { public std::iterator { private: + constexpr static const int COMPLETE = -1; typename std::remove_reference::type *container_p; std::vector> indicies; - int steps = 0; - bool done = false; + int steps{}; + + bool done() const { + return this->steps == COMPLETE; + } public: Iterator(Container& in_container, std::size_t n) @@ -54,8 +58,7 @@ namespace iter { indicies{n} { if (n == 0) { - this->done = true; - this->steps = -1; + this->steps = COMPLETE; return; } size_t inc = 0; @@ -66,7 +69,7 @@ namespace iter { iter = it; ++inc; } else { - done = true; + this->steps = COMPLETE; break; } } @@ -104,7 +107,7 @@ namespace iter { ++inc; } } else { - done = true; + this->steps = COMPLETE; break; } } else { @@ -113,7 +116,7 @@ namespace iter { //we break because none of the rest of the items need //to be incremented } - ++this->steps; + if (!this->done()) ++this->steps; return *this; } @@ -128,7 +131,7 @@ namespace iter { } bool operator==(const Iterator& other) const { - return (this->done && (this->done == other.done)) + return (this->done() && other.done()) || this->steps == other.steps; } }; From 66bd897805cfac683e27a67f13a3961a277f5e75 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 28 Jan 2015 18:45:41 -0500 Subject: [PATCH 0891/1866] grouper basic test --- catchtest/test_grouper.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 catchtest/test_grouper.cpp diff --git a/catchtest/test_grouper.cpp b/catchtest/test_grouper.cpp new file mode 100644 index 00000000..90457ba7 --- /dev/null +++ b/catchtest/test_grouper.cpp @@ -0,0 +1,25 @@ +#include + +#include +#include +#include +#include + +#include "helpers.hpp" +#include "catch.hpp" + +using iter::grouper; +using Vec = std::vector; +using ResVec = std::vector; + +TEST_CASE("grouper: basic test", "[grouper]") { + Vec ns = {1,2,3,4,5,6}; + ResVec results; + for (auto&& g : grouper(ns, 2)) { + results.emplace_back(std::begin(g), std::end(g)); + } + + ResVec rc = { {1, 2}, {3, 4}, {5, 6} }; + + REQUIRE( results == rc ); +} From 741ad83206a9f3244e5e10f7e603cbdf41af9600 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 28 Jan 2015 18:47:44 -0500 Subject: [PATCH 0892/1866] tests grouper when last group isn't full --- catchtest/test_grouper.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/catchtest/test_grouper.cpp b/catchtest/test_grouper.cpp index 90457ba7..397ebbd8 100644 --- a/catchtest/test_grouper.cpp +++ b/catchtest/test_grouper.cpp @@ -23,3 +23,15 @@ TEST_CASE("grouper: basic test", "[grouper]") { REQUIRE( results == rc ); } + +TEST_CASE("grouper: len(iterable) % groupsize != 0", "[grouper]") { + Vec ns = {1,2,3,4,5,6,7}; + ResVec results; + for (auto&& g : grouper(ns, 3)) { + results.emplace_back(std::begin(g), std::end(g)); + } + + ResVec rc = { {1, 2, 3}, {4, 5, 6}, {7} }; + + REQUIRE( results == rc ); +} From 6759f024c8466e5af6029ad72a9984c07f0166c7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 28 Jan 2015 18:48:04 -0500 Subject: [PATCH 0893/1866] a lot of changes to grouper iterator inherits from std::iterator operator== and postfix ++ for the iterator no more reference data member in iterator (iterators are assignable) iterators can actually be compared no more not_done operator* doesn't construct a temporary, it lives between calls --- grouper.hpp | 107 +++++++++++++++++++++++++--------------------------- 1 file changed, 52 insertions(+), 55 deletions(-) diff --git a/grouper.hpp b/grouper.hpp index 4fdcfec7..095edc0f 100644 --- a/grouper.hpp +++ b/grouper.hpp @@ -38,84 +38,81 @@ namespace iter { friend Grouper> grouper( std::initializer_list, std::size_t); + using DerefVec = std::vector>; public: - class Iterator { + class Iterator : + public std::iterator + { private: - Container& container; - std::vector> group; + iterator_type sub_iter; + iterator_type sub_end; + DerefVec group; std::size_t group_size = 0; - bool not_done = true; - - using Deref_type = - std::vector< - std::reference_wrapper< - typename std::remove_reference< - iterator_deref>::type>>; + bool done() const { + return this->group.empty(); + } - public: - Iterator(Container& c, std::size_t s) - : container(c), - group_size(s) - { - // if the group size is 0 or the container is empty produce - // nothing - if (this->group_size == 0 - || (!(std::begin(this->container) - != std::end(this->container)))) { - this->not_done = false; - return; - } - std::size_t i = 0; - for (auto iter = std::begin(container); - i < group_size; - ++i, ++iter) { - group.push_back(iter); + void refill_group() { + this->group.clear(); + std::size_t i{0}; + while (i < group_size + && this->sub_iter != this->sub_end) { + group.emplace_back(*this->sub_iter); + ++this->sub_iter; + ++i; } } - //seems like conclassor is same as sliding_window_iter - Iterator(Container& c) - : container(c) + public: + Iterator(iterator_type in_iter, + iterator_type in_end, + std::size_t s) + : sub_iter{std::move(in_iter)}, + sub_end{std::move(in_end)}, + group_size{s} { - //creates the end iterator - group.push_back(std::end(container)); + this->group.reserve(this->group_size); + this->refill_group(); } - //plan to conditionally check for existence of += - Iterator & operator++() { - for (auto & iter : this->group) { - std::advance(iter,this->group_size); - } + Iterator& operator++() { + this->refill_group(); return *this; } - bool operator!=(const Iterator &) const { - return this->not_done; + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; } - Deref_type operator*() { - Deref_type vec; - for (auto i : this->group) { - if(!(i != std::end(this->container))) { - this->not_done = false; - break; - } - //if the group is at the end the vector will be smaller - else { - vec.push_back(*i); - } - } - return vec; + bool operator!=(const Iterator& other) const { + return !(*this == other); + } + + bool operator==(const Iterator& other) const { + return this->done() == other.done() + && (this->done() + || !(this->sub_iter != other.sub_iter)); + } + + + DerefVec& operator*() { + return this->group; } }; Iterator begin() { - return {this->container, group_size}; + return {std::begin(this->container), + std::end(this->container), + group_size}; } Iterator end() { - return {this->container}; + return {std::end(this->container), + std::end(this->container), + group_size}; } }; From 2982bd74aee460c5967bca629f96dc1bc9d56c26 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 28 Jan 2015 18:51:52 -0500 Subject: [PATCH 0894/1866] builds grouper test --- catchtest/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index f05eecea..42bafa24 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -27,6 +27,7 @@ progs = Split( filter filterfalse groupby + grouper imap permutations powerset From 91cb5f4222324a85f07b2c67cdbc6da5e80d2ad4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 28 Jan 2015 18:58:16 -0500 Subject: [PATCH 0895/1866] tests grouper iterator comparisons --- catchtest/test_grouper.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/catchtest/test_grouper.cpp b/catchtest/test_grouper.cpp index 397ebbd8..917460c1 100644 --- a/catchtest/test_grouper.cpp +++ b/catchtest/test_grouper.cpp @@ -35,3 +35,15 @@ TEST_CASE("grouper: len(iterable) % groupsize != 0", "[grouper]") { REQUIRE( results == rc ); } + +TEST_CASE("grouper: iterators can be compared", "[grouper]") { + Vec ns = {1,2,3,4,5,6,7}; + auto g = grouper(ns, 3); + auto it = std::begin(g); + REQUIRE( it == std::begin(g) ); + REQUIRE_FALSE( it != std::begin(g) ); + ++it; + REQUIRE( it != std::begin(g) ); + REQUIRE_FALSE( it == std::begin(g) ); +} + From 79d0953b4296140d5028aa4892362825dde6377b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 28 Jan 2015 19:01:35 -0500 Subject: [PATCH 0896/1866] simplifies combinatons iterator comparison --- combinations.hpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/combinations.hpp b/combinations.hpp index 18475099..f42cb778 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -48,10 +48,6 @@ namespace iter { std::vector> indicies; int steps{}; - bool done() const { - return this->steps == COMPLETE; - } - public: Iterator(Container& in_container, std::size_t n) : container_p{&in_container}, @@ -116,7 +112,7 @@ namespace iter { //we break because none of the rest of the items need //to be incremented } - if (!this->done()) ++this->steps; + if (this->steps != COMPLETE) ++this->steps; return *this; } @@ -131,8 +127,7 @@ namespace iter { } bool operator==(const Iterator& other) const { - return (this->done() && other.done()) - || this->steps == other.steps; + return this->steps == other.steps; } }; From c3574a2394b289dc8f3f47fe8d104736554674c3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 28 Jan 2015 19:03:07 -0500 Subject: [PATCH 0897/1866] tests grouper with group size of 0 --- catchtest/test_grouper.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/catchtest/test_grouper.cpp b/catchtest/test_grouper.cpp index 917460c1..3397b307 100644 --- a/catchtest/test_grouper.cpp +++ b/catchtest/test_grouper.cpp @@ -47,3 +47,8 @@ TEST_CASE("grouper: iterators can be compared", "[grouper]") { REQUIRE_FALSE( it == std::begin(g) ); } +TEST_CASE("grouper: size 0 is empty", "[grouper]") { + Vec ns{1, 2, 3}; + auto g = grouper(ns, 0); + REQUIRE( std::begin(g) == std::end(g) ); +} From 57f1e094b2160d1d79cafe885ceb29f0d0faab93 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 28 Jan 2015 19:07:53 -0500 Subject: [PATCH 0898/1866] tests grouper with empty iterable --- catchtest/test_grouper.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/catchtest/test_grouper.cpp b/catchtest/test_grouper.cpp index 3397b307..27032464 100644 --- a/catchtest/test_grouper.cpp +++ b/catchtest/test_grouper.cpp @@ -52,3 +52,9 @@ TEST_CASE("grouper: size 0 is empty", "[grouper]") { auto g = grouper(ns, 0); REQUIRE( std::begin(g) == std::end(g) ); } + +TEST_CASE("grouper: empty iterable gives empty grouper", "[grouper]") { + Vec ns{}; + auto g = grouper(ns, 1); + REQUIRE( std::begin(g) == std::end(g) ); +} From a5b5918b3b9b740d3150dc274b9740dc46ecfa76 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 28 Jan 2015 19:37:42 -0500 Subject: [PATCH 0899/1866] makes comp_w_repl iterators actually compare --- combinations_with_replacement.hpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index 62e24db8..8a657d7c 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -50,15 +50,19 @@ namespace iter { CombIteratorDeref> { private: + constexpr static const int COMPLETE = -1; typename std::remove_reference::type *container_p; std::vector> indicies; - bool not_done; + int steps; public: Iterator(Container& in_container, std::size_t n) : container_p{&in_container}, indicies(n, std::begin(in_container)), - not_done{n != 0} + steps{(std::begin(in_container) + != std::end(in_container) + && n) + ? 0 : COMPLETE} { } CombIteratorDeref operator*() { @@ -83,7 +87,7 @@ namespace iter { (*down) = dumb_next(*(iter + 1)); } } else { - not_done = false; + this->steps = COMPLETE; break; } } else { @@ -92,6 +96,9 @@ namespace iter { break; } } + if (this->steps != COMPLETE) { + ++this->steps; + } return *this; } @@ -102,16 +109,12 @@ namespace iter { return ret; } - bool operator!=(const Iterator&) const { - //because of the way this is done you have to start from - //the begining of the range and end at the end, you - //could break in the middle of the loop though, it's not - //different from the way that python's works - return not_done; + bool operator!=(const Iterator& other) const { + return !(*this == other); } bool operator==(const Iterator& other) const { - return !(*this != other); + return this->steps == other.steps; } }; From 4f5628c00bf0f430adb56e2752998760a31dd072 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 28 Jan 2015 19:42:24 -0500 Subject: [PATCH 0900/1866] test that comb_with_repl moves and binds correctly --- .../test_combinations_with_replacement.cpp | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/catchtest/test_combinations_with_replacement.cpp b/catchtest/test_combinations_with_replacement.cpp index 6677009e..bfa688f1 100644 --- a/catchtest/test_combinations_with_replacement.cpp +++ b/catchtest/test_combinations_with_replacement.cpp @@ -10,30 +10,38 @@ using iter::combinations_with_replacement; using itertest::BasicIterable; -using CharCombSet = std::multiset>; +using CharCombSet = std::vector>; TEST_CASE("combinations_with_replacement: Simple combination", "[combinations_with_replacement]") { std::string s{"ABC"}; CharCombSet sc; for (auto v : combinations_with_replacement(s, 2)) { - std::vector vcopy(std::begin(v), std::end(v)); - sc.insert(vcopy); + sc.emplace_back(std::begin(v), std::end(v)); } CharCombSet ans = {{'A','A'}, {'A','B'}, {'A','C'}, {'B','B'}, {'B','C'}, {'C','C'}}; REQUIRE( ans == sc ); } - +TEST_CASE("combinations_with_replacement: iterators can be compared", + "[combinations_with_replacement]") { + std::string s{"ABCD"}; + auto c = combinations_with_replacement(s, 2); + auto it = std::begin(c); + REQUIRE( it == std::begin(c) ); + REQUIRE_FALSE( it != std::begin(c) ); + ++it; + REQUIRE( it != std::begin(c) ); + REQUIRE_FALSE( it == std::begin(c) ); +} TEST_CASE("combinations_with_replacement: big size is no problem", "[combinations_with_replacement]") { std::string s{"AB"}; CharCombSet sc; for (auto v : combinations_with_replacement(s, 3)) { - std::vector vcopy(std::begin(v), std::end(v)); - sc.insert(vcopy); + sc.emplace_back(std::begin(v), std::end(v)); } CharCombSet ans = {{'A', 'A', 'A'}, {'A', 'A', 'B'}, {'A', 'B', 'B'}, {'B', 'B', 'B'}}; @@ -47,8 +55,21 @@ TEST_CASE("combinations_with_replacement: 0 size is empty", REQUIRE( std::begin(cwr) == std::end(cwr) ); } +TEST_CASE("combinations_with_replacement: binds to lvalues, moves rvalues", + "[combinations_with_replacement]") { + BasicIterable bi{'x', 'y', 'z'}; + SECTION("binds to lvalues") { + combinations_with_replacement(bi, 1); + REQUIRE_FALSE( bi.was_moved_from() ); + } + SECTION("moves rvalues") { + combinations_with_replacement(std::move(bi), 1); + REQUIRE( bi.was_moved_from() ); + } +} -TEST_CASE("combinations_with_replacement: doesn't move or copy elements of iterable", +TEST_CASE("combinations_with_replacement: " + "doesn't move or copy elements of iterable", "[combinations_with_replacement]") { constexpr itertest::SolidInt arr[] = {{6}, {7}, {8}}; for (auto&& i : combinations_with_replacement(arr, 1)) { From 5eb242eaf3c85f72447832782a94346c0737dba9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Feb 2015 17:09:34 -0500 Subject: [PATCH 0901/1866] tests permutations iterator comparisons --- catchtest/test_permutations.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/catchtest/test_permutations.cpp b/catchtest/test_permutations.cpp index d6af74fb..23eec08f 100644 --- a/catchtest/test_permutations.cpp +++ b/catchtest/test_permutations.cpp @@ -35,6 +35,25 @@ TEST_CASE("permutations: empty sequence has one empy permutation", REQUIRE( it == std::end(p) ); } +TEST_CASE("permutations: iterators can be compared", "[permutations]") { + const std::vector ns = {1, 2}; + auto p = permutations(ns); + auto it = std::begin(p); + REQUIRE( it == std::begin(p) ); + REQUIRE_FALSE( it != std::begin(p) ); + REQUIRE( it != std::end(p) ); + REQUIRE_FALSE( it == std::end(p) ); + ++it; + REQUIRE_FALSE( it == std::begin(p) ); + REQUIRE( it != std::begin(p) ); + REQUIRE_FALSE( it == std::end(p) ); + REQUIRE( it != std::end(p) ); + ++it; + REQUIRE( it == std::end(p) ); + REQUIRE_FALSE( it != std::end(p) ); +} + + TEST_CASE("permutations: binds to lvalues, moves rvalues", "[permutations]") { itertest::BasicIterable bi{1, 2}; SECTION("binds to lvalues") { From a6e586bdff87cf3a69084d33a377c540c570a7b6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Feb 2015 17:09:52 -0500 Subject: [PATCH 0902/1866] makes permutations iterators actually comparable --- permutations.hpp | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/permutations.hpp b/permutations.hpp index 97ae6639..0db2af62 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -27,17 +27,22 @@ namespace iter { : public std::iterator { private: + constexpr static const int COMPLETE = -1; + Permutable working_set; - bool is_not_last = true; + int steps{}; public: - Iterator(Container& c) + Iterator(iterator_type sub_iter, + iterator_type sub_end) + : steps{ sub_iter != sub_end ? 0 : COMPLETE } { // done like this instead of using vector ctor with // two iterators because that causes a substitution // failure when the iterator is minimal - for (auto&& i : c) { - working_set.emplace_back(i); + while (sub_iter != sub_end) { + this->working_set.emplace_back(*sub_iter); + ++sub_iter; } std::sort(std::begin(working_set), std::end(working_set)); @@ -48,9 +53,11 @@ namespace iter { } Iterator& operator++() { - is_not_last = - std::next_permutation(std::begin(working_set), - std::end(working_set)); + ++this->steps; + if (!std::next_permutation(std::begin(working_set), + std::end(working_set))) { + this->steps = COMPLETE; + } return *this; } @@ -60,21 +67,23 @@ namespace iter { return ret; } - bool operator!=(const Iterator&) const { - return is_not_last; + bool operator!=(const Iterator& other) const { + return !(*this == other); } bool operator==(const Iterator& other) const { - return !(*this != other); + return this->steps == other.steps; } }; Iterator begin() { - return {this->container}; + return {std::begin(this->container), + std::end(this->container)}; } Iterator end() { - return {this->container}; + return {std::end(this->container), + std::end(this->container)}; } From fb438981ed1d2b4b3d2d0dbdaa35c5e8ba73ad5e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Feb 2015 17:24:00 -0500 Subject: [PATCH 0903/1866] tests that powerset iterators can be compared --- catchtest/test_powerset.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/catchtest/test_powerset.cpp b/catchtest/test_powerset.cpp index 7c22d558..1b4faeb7 100644 --- a/catchtest/test_powerset.cpp +++ b/catchtest/test_powerset.cpp @@ -31,6 +31,27 @@ TEST_CASE("powerset: empty sequence gives only empty set", "[powerset]") { REQUIRE( it == std::end(ps) ); } +TEST_CASE("powerset: iterators can be compared", "[powerset]") { + const std::vector ns = {1, 2}; + auto p = powerset(ns); + auto it = std::begin(p); + REQUIRE( it == std::begin(p) ); + REQUIRE_FALSE( it != std::begin(p) ); + REQUIRE( it != std::end(p) ); + REQUIRE_FALSE( it == std::end(p) ); + ++it; + REQUIRE_FALSE( it == std::begin(p) ); + REQUIRE( it != std::begin(p) ); + REQUIRE_FALSE( it == std::end(p) ); + REQUIRE( it != std::end(p) ); + ++it; + ++it; + ++it; + REQUIRE( it == std::end(p) ); + REQUIRE_FALSE( it != std::end(p) ); +} + + TEST_CASE("powerset: binds to lvalues, moves rvalues", "[powerset]") { itertest::BasicIterable bi{1, 2}; SECTION("binds to lvalues") { From 91ea563d546c92dac8c741483dcc0e22dbbf6dc5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Feb 2015 17:28:48 -0500 Subject: [PATCH 0904/1866] removes commented out code --- groupby.hpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index 718b4abc..81332e92 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -189,14 +189,6 @@ namespace iter { bool operator!=(const GroupIterator&) const { return !this->group.completed; -#if 0 - if (this->not_at_end()) { - return true; - } else { - this->group.completed = true; - return false; - } -#endif } bool operator==(const GroupIterator& other) const { From 00b3bfe7f2742e09f241c2523a3fc98658a355fb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Feb 2015 17:33:07 -0500 Subject: [PATCH 0905/1866] removes reference member in groupiterator So that the iterators are assignable. --- groupby.hpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index 81332e92..3af031d5 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -171,24 +171,24 @@ namespace iter { { private: const key_func_ret key; - const Group& group; + const Group* group_p; bool not_at_end() { - return !this->group.owner.exhausted()&& - this->group.owner.next_key() == this->key; + return !this->group_p->owner.exhausted()&& + this->group_p->owner.next_key() == this->key; } public: - GroupIterator(const Group& group, + GroupIterator(const Group& in_group, key_func_ret key) : key{key}, - group{group} + group_p{&in_group} { } GroupIterator(const GroupIterator&) = default; bool operator!=(const GroupIterator&) const { - return !this->group.completed; + return !this->group_p->completed; } bool operator==(const GroupIterator& other) const { @@ -196,9 +196,9 @@ namespace iter { } GroupIterator& operator++() { - this->group.owner.increment_iterator(); + this->group_p->owner.increment_iterator(); if (!this->not_at_end()) { - this->group.completed = true; + this->group_p->completed = true; } return *this; } @@ -210,7 +210,7 @@ namespace iter { } iterator_deref operator*() { - return this->group.owner.current(); + return this->group_p->owner.current(); } }; From 91b90b9b21ab2a85ef0938bc2ccb1cf8af06d82b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Feb 2015 17:52:01 -0500 Subject: [PATCH 0906/1866] actually compares in groupiter != once the group is complete, it's marked as completed and the iterator has its pointer set to nullptr. An end iterator always has a nullptr. --- groupby.hpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index 3af031d5..e5ad6988 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -152,7 +152,8 @@ namespace iter { } } - // movable, non-copyable + // move-constructible, non-copy-constructible, + // non-assignable Group() = delete; Group(const Group&) = delete; Group& operator=(const Group&) = delete; @@ -171,7 +172,7 @@ namespace iter { { private: const key_func_ret key; - const Group* group_p; + const Group *group_p; bool not_at_end() { return !this->group_p->owner.exhausted()&& @@ -179,26 +180,27 @@ namespace iter { } public: - GroupIterator(const Group& in_group, + GroupIterator(const Group *in_group_p, key_func_ret key) : key{key}, - group_p{&in_group} + group_p{in_group_p} { } GroupIterator(const GroupIterator&) = default; - bool operator!=(const GroupIterator&) const { - return !this->group_p->completed; + bool operator!=(const GroupIterator& other) const { + return !(*this == other); } bool operator==(const GroupIterator& other) const { - return !(*this != other); + return this->group_p == other.group_p; } GroupIterator& operator++() { this->group_p->owner.increment_iterator(); if (!this->not_at_end()) { this->group_p->completed = true; + this->group_p = nullptr; } return *this; } @@ -215,11 +217,11 @@ namespace iter { }; GroupIterator begin() { - return {*this, key}; + return {this, key}; } GroupIterator end() { - return {*this, key}; + return {nullptr, key}; } }; From edcc49d3a7354f482c3c91519bb1fda20ec186ec Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Feb 2015 17:54:41 -0500 Subject: [PATCH 0907/1866] removes const on key it groupiterator --- groupby.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/groupby.hpp b/groupby.hpp index e5ad6988..ce12ae6c 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -171,7 +171,7 @@ namespace iter { iterator_traits_deref> { private: - const key_func_ret key; + key_func_ret key; const Group *group_p; bool not_at_end() { From 7106a45979f13c2c28cf4ee0f22f9ace2a4737f9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Feb 2015 17:57:54 -0500 Subject: [PATCH 0908/1866] const corrector in groupiter and group --- groupby.hpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index ce12ae6c..c9cb15f2 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -136,7 +136,7 @@ namespace iter { // The move constructor sets the rvalue's completed // attribute to true, so its destructor doesn't do anything // when called. - mutable bool completed = false; + bool completed = false; Group(Iterator& owner, key_func_ret key) : owner(owner), @@ -172,7 +172,7 @@ namespace iter { { private: key_func_ret key; - const Group *group_p; + Group *group_p; bool not_at_end() { return !this->group_p->owner.exhausted()&& @@ -180,14 +180,12 @@ namespace iter { } public: - GroupIterator(const Group *in_group_p, + GroupIterator(Group *in_group_p, key_func_ret key) : key{key}, group_p{in_group_p} { } - GroupIterator(const GroupIterator&) = default; - bool operator!=(const GroupIterator& other) const { return !(*this == other); } From 8aefcc7e71feb56e67bb451ce8b83ed102e74179 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Feb 2015 18:04:00 -0500 Subject: [PATCH 0909/1866] uses std::result_of for key_func_ret --- groupby.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index c9cb15f2..740a5162 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -3,6 +3,7 @@ #include "iterbase.hpp" +#include #include #include #include @@ -31,9 +32,8 @@ namespace iter { friend GroupBy, KF> groupby( std::initializer_list, KF); - using key_func_ret = - decltype(std::declval()( - std::declval>())); + using key_func_ret = typename + std::result_of)>::type; GroupBy(Container&& container, KeyFunc key_func) : container(std::forward(container)), From 14b3cd49982d3a3a9dc6fc0acb150c6df3f136e2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Feb 2015 19:40:59 -0500 Subject: [PATCH 0910/1866] tests groupby with different functor types --- catchtest/test_groupby.cpp | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/catchtest/test_groupby.cpp b/catchtest/test_groupby.cpp index a1fbae32..6b67f16d 100644 --- a/catchtest/test_groupby.cpp +++ b/catchtest/test_groupby.cpp @@ -15,20 +15,43 @@ namespace { return s.size(); } + struct Sizer { + int operator()(const std::string& s) { + return s.size(); + } + }; + const std::vector vec = { "hi", "ab", "ho", "abc", "def", "abcde", "efghi" }; - } -TEST_CASE("groupby: groups words by length") { +TEST_CASE("groupby: works with lambda, callable, and function pointer") { std::vector keys; std::vector> groups; - for (auto&& gb : groupby(vec, &length)) { - keys.push_back(gb.first); - groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + + SECTION("Function pointer") { + for (auto&& gb : groupby(vec, length)) { + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + } + } + + SECTION("Callable object") { + for (auto&& gb : groupby(vec, Sizer{})) { + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + } + } + + SECTION("lambda function") { + for (auto&& gb : groupby(vec, + [](const std::string& s){return s.size();})) { + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + } } const std::vector kc = {2, 3, 5}; From 46234fabb40c3c78a8adba435447d5e0353b6124 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Feb 2015 20:06:56 -0500 Subject: [PATCH 0911/1866] iterators are actually compared --- groupby.hpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index 740a5162..42768202 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -75,11 +75,10 @@ namespace iter { { } KeyGroupPair operator*() { - return KeyGroupPair( - this->key_func(*this->sub_iter), - Group( - *this, - this->key_func(*this->sub_iter))); + return { + this->key_func(*this->sub_iter), + Group{*this, this->key_func(*this->sub_iter)} + }; } Iterator& operator++() { @@ -92,8 +91,8 @@ namespace iter { return ret; } - bool operator!=(const Iterator&) const { - return !this->exhausted(); + bool operator!=(const Iterator& other) const { + return this->sub_iter != other.sub_iter; } bool operator==(const Iterator& other) const { From 25342c0cfdc62b006686df272bdfec4f39d66558 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Feb 2015 20:58:37 -0500 Subject: [PATCH 0912/1866] combinations build vectors in * instead of ++ --- combinations.hpp | 24 +++++++++++++++++------- combinations_with_replacement.hpp | 21 ++++++++++++++------- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/combinations.hpp b/combinations.hpp index f42cb778..4f560ef1 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -46,8 +46,16 @@ namespace iter { constexpr static const int COMPLETE = -1; typename std::remove_reference::type *container_p; std::vector> indicies; + CombIteratorDeref working_set; int steps{}; + void compute_working_set() { + this->working_set.clear(); + for (auto&& i : this->indicies) { + this->working_set.emplace_back(*i); + } + } + public: Iterator(Container& in_container, std::size_t n) : container_p{&in_container}, @@ -69,14 +77,13 @@ namespace iter { break; } } + if (this->steps != COMPLETE) { + this->compute_working_set(); + } } - CombIteratorDeref operator*() { - CombIteratorDeref values; - for (auto i : indicies) { - values.push_back(*i); - } - return values; + CombIteratorDeref& operator*() { + return this->working_set; } @@ -112,7 +119,10 @@ namespace iter { //we break because none of the rest of the items need //to be incremented } - if (this->steps != COMPLETE) ++this->steps; + if (this->steps != COMPLETE) { + ++this->steps; + this->compute_working_set(); + } return *this; } diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index 8a657d7c..429a0c5a 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -53,8 +53,16 @@ namespace iter { constexpr static const int COMPLETE = -1; typename std::remove_reference::type *container_p; std::vector> indicies; + CombIteratorDeref working_set; int steps; + void compute_working_set() { + this->working_set.clear(); + for (auto&& i : indicies) { + this->working_set.emplace_back(*i); + } + } + public: Iterator(Container& in_container, std::size_t n) : container_p{&in_container}, @@ -63,14 +71,12 @@ namespace iter { != std::end(in_container) && n) ? 0 : COMPLETE} - { } + { + this->compute_working_set(); + } - CombIteratorDeref operator*() { - std::vector> values; - for (auto i : indicies) { - values.push_back(*i); - } - return values; + CombIteratorDeref& operator*() { + return this->working_set; } @@ -98,6 +104,7 @@ namespace iter { } if (this->steps != COMPLETE) { ++this->steps; + this->compute_working_set(); } return *this; } From fefc24241da036352d8cb45ef18304a45985f455 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 12:58:45 -0500 Subject: [PATCH 0913/1866] adds test for iteratoriterator --- catchtest/test_iteratoriterator.cpp | 54 +++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 catchtest/test_iteratoriterator.cpp diff --git a/catchtest/test_iteratoriterator.cpp b/catchtest/test_iteratoriterator.cpp new file mode 100644 index 00000000..e034cc71 --- /dev/null +++ b/catchtest/test_iteratoriterator.cpp @@ -0,0 +1,54 @@ +#include + +#include +#include + +#include "catch.hpp" + +using iter::IterIterWrapper; + +TEST_CASE("Iterator over a vector of vector iterators", "[iteratoriterator]") { + using std::vector; + vector v = {2, 4, 6, 8}; + + IterIterWrapper::iterator>> itr; + itr.get().push_back(std::begin(v) + 1); + itr.get().push_back(std::end(v) - 1); + itr.get().push_back(std::begin(v)); + + auto it = std::begin(itr); + REQUIRE( *it == 4 ); + REQUIRE( it != std::end(itr) ); + ++it; + REQUIRE( *it == 8 ); + it++; + REQUIRE( *it == 2 ); + ++it; + REQUIRE( it == std::end(itr) ); + + REQUIRE( itr[0] == 4 ); + REQUIRE( itr[1] == 8 ); + REQUIRE( itr[2] == 2 ); + + auto rit = itr.rbegin(); + + REQUIRE( *rit == 2 ); + REQUIRE( rit != itr.rend() ); + ++rit; + REQUIRE( *rit == 8 ); + ++rit; + REQUIRE( *rit == 4 ); + ++rit; + REQUIRE( rit == itr.rend() ); +} + +TEST_CASE("IteratorIterator operator->", "[iteratoriterator]") { + using std::vector; + using std::string; + vector v = {"hello", "everyone"}; + IterIterWrapper::iterator>> itritr; + itritr.get().push_back(std::end(v) - 1); + itritr.get().push_back(std::begin(v)); + auto it = std::begin(itritr); + REQUIRE( it->size() == 8 ); +} From 8d56fd47a32511c9671b2fe74a98238504a6cebd Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 12:58:58 -0500 Subject: [PATCH 0914/1866] adds iteratoriterator --- iteratoriterator.hpp | 219 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100644 iteratoriterator.hpp diff --git a/iteratoriterator.hpp b/iteratoriterator.hpp new file mode 100644 index 00000000..cb0d0143 --- /dev/null +++ b/iteratoriterator.hpp @@ -0,0 +1,219 @@ +#ifndef ITERATOR_ITERATOR_HPP_ +#define ITERATOR_ITERATOR_HPP_ + +#include "iterbase.hpp" +#include "zip.hpp" +#include +#include +#include + +// IterIterWrapper and IteratorIterator provide a means to have a container +// of iterators act like a container of the pointed to objects. This is useful +// for combinatorics and similar itertools which need to keep track of +// more than one element at a time. +// an IterIterWrapper::iterator>> +// behave like some_collection when iterated over or indexed + +namespace iter { + template ::difference_type> + class IteratorIterator : public std::iterator< + std::random_access_iterator_tag, + typename std::iterator_traits::value_type, + Diff, + typename std::iterator_traits::pointer, + typename std::iterator_traits::reference + > + { + static_assert(std::is_same< + typename std::iterator_traits::iterator_category, + std::random_access_iterator_tag>::value, + "IteratorIterator only works with random access iterators"); + private: + Iter sub_iter; + public: + IteratorIterator() = default; + IteratorIterator(const Iter& it) + : sub_iter{it} + { } + + bool operator==(const IteratorIterator& other) const { + return !(*this != other); + } + + bool operator!=(const IteratorIterator& other) const { + return this->sub_iter != other.sub_iter; + } + + IteratorIterator& operator++() { + ++this->sub_iter; + return *this; + } + + IteratorIterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + IteratorIterator& operator--() { + --this->sub_iter; + return *this; + } + + IteratorIterator operator--(int) { + auto ret = *this; + --*this; + return ret; + } + + auto operator*() -> decltype(**sub_iter) { + return **this->sub_iter; + } + + auto operator->() -> decltype(*sub_iter) { + return *this->sub_iter; + } + + + IteratorIterator& operator+=(Diff n) { + this->sub_iter += n; + return *this; + } + + IteratorIterator operator+(Diff n) const { + auto it = *this; + it += n; + return it; + } + + friend IteratorIterator operator+(Diff n, IteratorIterator it) { + it += n; + return it; + } + + IteratorIterator& operator-=(Diff n) { + this->sub_iter -= n; + return *this; + } + + IteratorIterator operator-(Diff n) const { + auto it = *this; + it -= n; + return it; + } + + friend IteratorIterator operator-(Diff n, IteratorIterator it) { + it -= n; + return it; + } + + Diff operator-(const IteratorIterator& rhs) const { + return this->sub_iter - rhs.sub_iter; + } + + auto operator[](Diff idx) -> decltype(*sub_iter[idx]) { + return *sub_iter[idx]; + } + + bool operator<(const IteratorIterator& rhs) const { + return this->sub_iter < rhs.sub_iter; + } + + bool operator>(const IteratorIterator& rhs) const { + return this->sub_iter > rhs.sub_iter; + } + + bool operator<=(const IteratorIterator& rhs) const { + return this->sub_iter <= rhs.sub_iter; + } + + bool operator>=(const IteratorIterator& rhs) const { + return this->sub_iter >= rhs.sub_iter; + } + }; + + template + class IterIterWrapper { + private: + Container container; + + using contained_iter = typename Container::value_type; + using size_type = typename Container::size_type; + using iterator = + IteratorIterator; + using reverse_iterator = + IteratorIterator; + + public: + IterIterWrapper() = default; + + explicit IterIterWrapper(size_type sz) + : container(sz) + { } + + IterIterWrapper(size_type sz, const contained_iter& val) + : container(sz, val) + { } + + auto at(size_type pos) -> decltype(*container.at(pos)) { + return *container.at(pos); + } + + auto at(size_type pos) const -> decltype(*container.at(pos)) { + return *container.at(pos); + } + + auto operator[](size_type pos) + noexcept(noexcept(*container[pos])) + -> decltype(*container[pos]) + { + return *container[pos]; + } + + auto operator[](size_type pos) const + noexcept(noexcept(*container[pos])) + -> decltype(*container[pos]) + { + return *container[pos]; + } + + bool empty() const noexcept { + return container.empty(); + } + + size_type size() const noexcept { + return container.size(); + } + + iterator begin() noexcept { + return {container.begin()}; + } + + iterator end() noexcept { + return {container.end()}; + } + + reverse_iterator rbegin() noexcept { + return {container.rbegin()}; + } + + reverse_iterator rend() noexcept { + return {container.rend()}; + } + + // get() exposes the underlying container. this allows the + // itertools to manipulate the iterators in the container + // and should not be depended on anywhere else. + Container& get() noexcept { + return container; + } + + const Container& get() const noexcept { + return container; + } + + }; +} + +#endif From 916b46f97225f021e0285108f659512f471dc349 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 12:59:11 -0500 Subject: [PATCH 0915/1866] bulids iteratoriterator tests --- catchtest/SConstruct | 2 ++ 1 file changed, 2 insertions(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index 42bafa24..0a8c1e35 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -43,6 +43,8 @@ progs = Split( unique_justseen zip zip_longest + + iteratoriterator ''' ) From 84d75a345692e68f4a52c6864e43bbab65f4a5d7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 12:59:45 -0500 Subject: [PATCH 0916/1866] combinations uses iteratoriterator --- combinations.hpp | 38 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/combinations.hpp b/combinations.hpp index 4f560ef1..a2cfeda2 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -2,6 +2,7 @@ #define ITER_COMBINATIONS_HPP_ #include "iterbase.hpp" +#include "iteratoriterator.hpp" #include #include @@ -35,8 +36,9 @@ namespace iter { length{in_length} { } - using CombIteratorDeref = - std::vector>; + using IndexVector = std::vector>; + using CombIteratorDeref = IterIterWrapper; + public: class Iterator : @@ -45,28 +47,20 @@ namespace iter { private: constexpr static const int COMPLETE = -1; typename std::remove_reference::type *container_p; - std::vector> indicies; - CombIteratorDeref working_set; + CombIteratorDeref indices; int steps{}; - void compute_working_set() { - this->working_set.clear(); - for (auto&& i : this->indicies) { - this->working_set.emplace_back(*i); - } - } - public: Iterator(Container& in_container, std::size_t n) : container_p{&in_container}, - indicies{n} + indices{n} { if (n == 0) { this->steps = COMPLETE; return; } size_t inc = 0; - for (auto& iter : this->indicies) { + for (auto& iter : this->indices.get()) { auto it = std::begin(*this->container_p); dumb_advance(it, std::end(*this->container_p), inc); if (it != std::end(*this->container_p)) { @@ -77,34 +71,31 @@ namespace iter { break; } } - if (this->steps != COMPLETE) { - this->compute_working_set(); - } } CombIteratorDeref& operator*() { - return this->working_set; + return this->indices; } Iterator& operator++() { - for (auto iter = indicies.rbegin(); - iter != indicies.rend(); + for (auto iter = indices.get().rbegin(); + iter != indices.get().rend(); ++iter) { ++(*iter); //what we have to check here is if the distance between - //the index and the end of indicies is >= the distance + //the index and the end of indices is >= the distance //between the item and end of item auto dist = std::distance( - this->indicies.rbegin(),iter); + this->indices.get().rbegin(),iter); if (!(dumb_next(*iter, dist) != std::end(*this->container_p))) { - if ( (iter + 1) != indicies.rend()) { + if ( (iter + 1) != indices.get().rend()) { size_t inc = 1; for (auto down = iter; - down != indicies.rbegin()-1; + down != indices.get().rbegin()-1; --down) { (*down) = dumb_next(*(iter + 1), 1 + inc); ++inc; @@ -121,7 +112,6 @@ namespace iter { } if (this->steps != COMPLETE) { ++this->steps; - this->compute_working_set(); } return *this; } From 0100c4fe796bcf42d128a4d1e0b07d48277a7ff8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 12:59:59 -0500 Subject: [PATCH 0917/1866] comb_w_repl uses iteratoriterator --- combinations_with_replacement.hpp | 32 +++++++++++-------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index 429a0c5a..bfb8a9b1 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -2,6 +2,7 @@ #define ITER_COMBINATIONS_WITH_REPLACEMENT_HPP_ #include "iterbase.hpp" +#include "iteratoriterator.hpp" #include #include @@ -41,8 +42,8 @@ namespace iter { length{n} { } - using CombIteratorDeref = - std::vector>; + using IndexVector = std::vector>; + using CombIteratorDeref = IterIterWrapper; public: class Iterator : @@ -52,43 +53,33 @@ namespace iter { private: constexpr static const int COMPLETE = -1; typename std::remove_reference::type *container_p; - std::vector> indicies; - CombIteratorDeref working_set; + CombIteratorDeref indices; int steps; - void compute_working_set() { - this->working_set.clear(); - for (auto&& i : indicies) { - this->working_set.emplace_back(*i); - } - } - public: Iterator(Container& in_container, std::size_t n) : container_p{&in_container}, - indicies(n, std::begin(in_container)), + indices(n, std::begin(in_container)), steps{(std::begin(in_container) != std::end(in_container) && n) ? 0 : COMPLETE} - { - this->compute_working_set(); - } + { } CombIteratorDeref& operator*() { - return this->working_set; + return this->indices; } Iterator& operator++() { - for (auto iter = indicies.rbegin(); - iter != indicies.rend(); + for (auto iter = indices.get().rbegin(); + iter != indices.get().rend(); ++iter) { ++(*iter); if (!(*iter != std::end(*this->container_p))) { - if ( (iter + 1) != indicies.rend()) { + if ( (iter + 1) != indices.get().rend()) { for (auto down = iter; - down != indicies.rbegin()-1; + down != indices.get().rbegin()-1; --down) { (*down) = dumb_next(*(iter + 1)); } @@ -104,7 +95,6 @@ namespace iter { } if (this->steps != COMPLETE) { ++this->steps; - this->compute_working_set(); } return *this; } From d3875a5bed5cdbe426f2b4fe5b62fa162a03600b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 13:01:06 -0500 Subject: [PATCH 0918/1866] perumations uses iteratoriterator --- permutations.hpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/permutations.hpp b/permutations.hpp index 0db2af62..c16a8f4e 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -1,6 +1,8 @@ #ifndef ITER_PERMUTATIONS_HPP_ #define ITER_PERMUTATIONS_HPP_ + #include "iterbase.hpp" +#include "iteratoriterator.hpp" #include #include @@ -15,8 +17,8 @@ namespace iter { private: Container container; - using Permutable = - std::vector>; + using IndexVector = std::vector>; + using Permutable = IterIterWrapper; public: Permuter(Container&& in_container) @@ -27,7 +29,12 @@ namespace iter { : public std::iterator { private: - constexpr static const int COMPLETE = -1; + static constexpr const int COMPLETE = -1; + static bool cmp_iters( + const iterator_type& lhs, + const iterator_type& rhs) noexcept { + return *lhs < *rhs; + } Permutable working_set; int steps{}; @@ -41,11 +48,12 @@ namespace iter { // two iterators because that causes a substitution // failure when the iterator is minimal while (sub_iter != sub_end) { - this->working_set.emplace_back(*sub_iter); + this->working_set.get().push_back(sub_iter); ++sub_iter; } - std::sort(std::begin(working_set), - std::end(working_set)); + std::sort(std::begin(working_set.get()), + std::end(working_set.get()), + cmp_iters); } Permutable& operator*() { @@ -54,8 +62,8 @@ namespace iter { Iterator& operator++() { ++this->steps; - if (!std::next_permutation(std::begin(working_set), - std::end(working_set))) { + if (!std::next_permutation(std::begin(working_set.get()), + std::end(working_set.get()), cmp_iters)) { this->steps = COMPLETE; } return *this; From cebf14704171d0a2ef0bb0f651572fd04c8b42c7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 13:01:21 -0500 Subject: [PATCH 0919/1866] sliding window uses iteratoriterator --- sliding_window.hpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sliding_window.hpp b/sliding_window.hpp index 4efdf7d1..94cc66e7 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -2,6 +2,7 @@ #define ITER_SLIDING_WINDOW_HPP_ #include "iterbase.hpp" +#include "iteratoriterator.hpp" #include #include @@ -35,7 +36,8 @@ namespace iter { window_size{win_sz} { } - using DerefVec = std::deque>; + using IndexVector = std::deque>; + using DerefVec = IterIterWrapper; public: class Iterator @@ -53,7 +55,7 @@ namespace iter { { std::size_t i{0}; while (i < window_sz && this->sub_iter != in_end) { - this->window.push_back(*this->sub_iter); + this->window.get().push_back(this->sub_iter); ++i; if (i != window_sz) ++this->sub_iter; } @@ -73,8 +75,8 @@ namespace iter { Iterator& operator++() { ++this->sub_iter; - this->window.pop_front(); - this->window.push_back(*this->sub_iter); + this->window.get().pop_front(); + this->window.get().push_back(this->sub_iter); return *this; } From c5e606d982d1db9867734632a3a42b907b130d8d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 13:01:32 -0500 Subject: [PATCH 0920/1866] grouper uses iteratoriterator --- grouper.hpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/grouper.hpp b/grouper.hpp index 095edc0f..3cb69fe1 100644 --- a/grouper.hpp +++ b/grouper.hpp @@ -2,6 +2,7 @@ #define ITER_GROUPER_HPP_ #include "iterbase.hpp" +#include "iteratoriterator.hpp" #include #include @@ -38,7 +39,8 @@ namespace iter { friend Grouper> grouper( std::initializer_list, std::size_t); - using DerefVec = std::vector>; + using IndexVector = std::vector>; + using DerefVec = IterIterWrapper; public: class Iterator : public std::iterator @@ -54,11 +56,11 @@ namespace iter { } void refill_group() { - this->group.clear(); + this->group.get().clear(); std::size_t i{0}; while (i < group_size && this->sub_iter != this->sub_end) { - group.emplace_back(*this->sub_iter); + group.get().push_back(this->sub_iter); ++this->sub_iter; ++i; } @@ -72,7 +74,7 @@ namespace iter { sub_end{std::move(in_end)}, group_size{s} { - this->group.reserve(this->group_size); + this->group.get().reserve(this->group_size); this->refill_group(); } From a070c151c71a7a42f2723e03f8bdb784c4743fca Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 13:01:45 -0500 Subject: [PATCH 0921/1866] removes collection_item_type (now unused) --- iterbase.hpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/iterbase.hpp b/iterbase.hpp index 81f6ff95..0f0fe1bc 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -42,19 +42,6 @@ namespace iter { using reverse_iterator_deref = decltype(*std::declval&>()); - // For combinatoric functions, if the Containers iterator dereferences - // to a reference, then this is a std::reference_wrapper for that type - // otherwise it's a non-const of that type - template - using collection_item_type = - typename std::conditional< - std::is_reference>::value, - std::reference_wrapper< - typename std::remove_reference< - iterator_deref>::type>, - typename std::remove_const< - iterator_deref>::type>::type; - template struct is_random_access_iter : std::false_type { }; From 8a9eb9802efe146bc94a84f31899fe2fe6054740 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 13:10:24 -0500 Subject: [PATCH 0922/1866] sorted uses stock iteratoriterator --- iteratoriterator.hpp | 2 +- sorted.hpp | 45 ++++++++++++++------------------------------ 2 files changed, 15 insertions(+), 32 deletions(-) diff --git a/iteratoriterator.hpp b/iteratoriterator.hpp index cb0d0143..5bd807bc 100644 --- a/iteratoriterator.hpp +++ b/iteratoriterator.hpp @@ -74,7 +74,7 @@ namespace iter { auto operator->() -> decltype(*sub_iter) { return *this->sub_iter; } - + IteratorIterator& operator+=(Diff n) { this->sub_iter += n; diff --git a/sorted.hpp b/sorted.hpp index 05c5a3e3..5dbbdc9b 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -2,6 +2,7 @@ #define ITER_SORTED_HPP_ #include "iterbase.hpp" +#include "iteratoriterator.hpp" #include #include @@ -17,17 +18,15 @@ namespace iter { template class Sorted { private: - Container container; - std::vector> sorted_iters; - + using IterIterWrap = + IterIterWrapper>>; + using ItIt = iterator_type; friend Sorted sorted(Container&&, CompareFunc); - using sorted_iter_type = iterator_type; - + Container container; + IterIterWrap sorted_iters; - Sorted() = delete; - Sorted& operator=(const Sorted&) = delete; Sorted(Container&& in_container, CompareFunc compare_func) : container(std::forward(in_container)) @@ -37,42 +36,26 @@ namespace iter { for (auto iter = std::begin(this->container); iter != std::end(this->container); ++iter) { - this->sorted_iters.push_back(iter); + this->sorted_iters.get().push_back(iter); } // sort by comparing the elements that the iterators point to - std::sort(std::begin(sorted_iters), std::end(sorted_iters), - [&] (const iterator_type& it1, + std::sort(std::begin(sorted_iters.get()), + std::end(sorted_iters.get()), + [compare_func] (const iterator_type& it1, const iterator_type& it2) { return compare_func(*it1, *it2); }); } public: - Sorted(const Sorted&) = default; - - // Iterates over a series of Iterators, automatically dereferencing - // them when accessed with operator * - class IteratorIterator : public sorted_iter_type { - public: - IteratorIterator(sorted_iter_type iter) - : sorted_iter_type{iter} - { } - IteratorIterator(const IteratorIterator&) = default; - - // Dereference the current iterator before returning - iterator_deref operator*() { - return *sorted_iter_type::operator*(); - } - }; - - IteratorIterator begin() { - return {std::begin(sorted_iters)}; + ItIt begin() { + return std::begin(sorted_iters); } - IteratorIterator end() { - return {std::end(sorted_iters)}; + ItIt end() { + return std::end(sorted_iters); } }; From 13924b0724677e4af38a03d86272172d31244a79 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 17:03:19 -0500 Subject: [PATCH 0923/1866] 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 0924/1866] 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 0925/1866] 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 0926/1866] 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 0927/1866] 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 0928/1866] 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 0929/1866] 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 0930/1866] 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 0931/1866] 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 0932/1866] 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 0933/1866] 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 0934/1866] 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 0935/1866] 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 0936/1866] 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 0937/1866] 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 0938/1866] 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 0939/1866] 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 0940/1866] 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 0941/1866] 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 0942/1866] 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 0943/1866] 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 0944/1866] 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 0945/1866] 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 0946/1866] 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 0947/1866] 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 0948/1866] 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 0949/1866] 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 eed7e888ffd646af253c3a7dbe0ea8291ebcb102 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 11 Feb 2015 17:02:11 -0500 Subject: [PATCH 0950/1866] removes const on iterator member --- product.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/product.hpp b/product.hpp index 92e0c5b8..d95d8060 100644 --- a/product.hpp +++ b/product.hpp @@ -50,7 +50,7 @@ namespace iter { const iterator_type begin; RestIter rest_iter; - const RestIter rest_end; + RestIter rest_end; public: constexpr static const bool is_base_iter = false; Iterator(iterator_type it, From e4fabf39fefb6b0dda5cdc5c2d5ce5af80587c42 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 12 Feb 2015 19:03:02 -0500 Subject: [PATCH 0951/1866] uses implicit tuple<> construction --- product.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/product.hpp b/product.hpp index d95d8060..aaf0f42d 100644 --- a/product.hpp +++ b/product.hpp @@ -145,7 +145,7 @@ namespace iter { } std::tuple<> operator*() const { - return std::tuple<>{}; + return {}; } }; From 62a05115bb53a5aec2b62d380f082041a6c57164 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 11:06:54 -0500 Subject: [PATCH 0952/1866] adds helper to hold intermittent results of deref For things like filter that may need to dereference multiple times. Doing so violates the input_iterator guarantees. --- iterbase.hpp | 83 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 79 insertions(+), 4 deletions(-) diff --git a/iterbase.hpp b/iterbase.hpp index 0f0fe1bc..aacd2246 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -11,8 +11,9 @@ #include #include #include -#include +#include #include +#include namespace iter { @@ -24,7 +25,7 @@ namespace iter { // iterator_deref is the type obtained by dereferencing an iterator // to an object of type C template - using iterator_deref = + using iterator_deref = decltype(*std::declval&>()); template @@ -39,7 +40,7 @@ namespace iter { // iterator_deref is the type obtained by dereferencing an iterator // to an object of type C template - using reverse_iterator_deref = + using reverse_iterator_deref = decltype(*std::declval&>()); template @@ -118,9 +119,83 @@ namespace iter { struct are_same : std::true_type { }; template - struct are_same + struct are_same : std::integral_constant::value && are_same::value> { }; + + template + class DerefHolder { + private: + 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; + + std::unique_ptr item_p; + + public: + explicit DerefHolder() + : item_p{nullptr} + { } + + DerefHolder(const DerefHolder& other) + : item_p{new TPlain(*other.item_p)} + { } + + DerefHolder& operator=(const DerefHolder& other) { + this->item_p.reset(new TPlain(*other.item_p)); + return *this; + } + + DerefHolder(DerefHolder&&) = default; + DerefHolder& operator=(DerefHolder&&) = default; + ~DerefHolder() = default; + + TPlain& get() { + return *item_p; + } + + T pull() { + return std::move(*item_p); + // NOTE should I reset the unique_ptr to nullptr here + // since its held item is now invalid anyway? + } + + void reset(T&& item) { + item_p.reset(new TPlain(std::move(item))); + } + }; + + + // Specialization for when T is an lvalue ref. Keep this in mind + // wherever a T appears. + template + class DerefHolder::value>::type> + { + private: + static_assert(std::is_lvalue_reference::value, + "lvalue specialization handling non-lvalue-ref type"); + typename std::remove_reference::type *item_p; + public: + explicit DerefHolder() + : item_p{nullptr} + { } + + T get() { + return *this->item_p; + } + + T pull() { + return this->get(); + } + + void reset(T item) { + this->item_p = &item; + } + }; + + } #endif From 6feffa46aa0026d55736a3187e6fdbde01b7a930 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 11:08:27 -0500 Subject: [PATCH 0953/1866] tests imap(filter(imap())) Currently a problem with modifying function --- catchtest/test_mixed.cpp | 82 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 catchtest/test_mixed.cpp diff --git a/catchtest/test_mixed.cpp b/catchtest/test_mixed.cpp new file mode 100644 index 00000000..d3618348 --- /dev/null +++ b/catchtest/test_mixed.cpp @@ -0,0 +1,82 @@ +// mixing different itertools, there is nothing called iter::mixed() + + +#include "imap.hpp" +#include "filter.hpp" + +#include "catch.hpp" + +#include +#include + +using iter::filter; +using iter::imap; + +class MyUnMovable { + int val; +public: + constexpr MyUnMovable(int val) + : val{val} + { } + + MyUnMovable(const MyUnMovable&) = delete; + MyUnMovable& operator=(const MyUnMovable&) = delete; + + MyUnMovable(MyUnMovable&& other) + : val{other.val} + { } + + constexpr int get_val() const { + return val; + } + void set_val(int val) { + this->val = val; + } + + bool operator==(const MyUnMovable& other) const { + return this->val == other.val; + } + + bool operator!=(const MyUnMovable& other) const { + return !(*this == other); + } +}; + +TEST_CASE("imap and filter where imap Functor modifies its sequence", + "[imap][filter]") { + + // source data + std::array arr = {{{41}, {42}, {43}}}; + + // some transformations + auto inc_ten = [](MyUnMovable& el) -> MyUnMovable& { + int va = el.get_val(); + el.set_val(va + 10); + return el; + }; + auto dec_ten = [](MyUnMovable& el) -> MyUnMovable& { + int va = el.get_val(); + el.set_val(va - 10); + return el; + }; + + auto transformed1 = imap(inc_ten, arr); + auto filtered = filter([](const MyUnMovable& el) { + return 52 != el.get_val(); + }, transformed1); + auto transformed2 = imap(dec_ten, filtered); + + std::vector v; + for (auto&& el : transformed2) { + // I would use imap again instead of the loop if this wasn't an imap + // test + v.push_back(el.get_val()); + } + + std::vector vc = {41, 43}; + + REQUIRE( v == vc); + + constexpr std::array arrc = {{{41}, {52}, {43}}}; + REQUIRE( arr == arrc ); +} From 66ff1840d29d9d26ba8d7d0ed8d4e728e7495e75 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 11:13:37 -0500 Subject: [PATCH 0954/1866] Uses DerefHolder to avoid double-deref previous deref'd in operator++ (skip_failures) and in operator* --- filter.hpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/filter.hpp b/filter.hpp index fdefe612..54947c5d 100644 --- a/filter.hpp +++ b/filter.hpp @@ -49,14 +49,22 @@ namespace iter { protected: iterator_type sub_iter; iterator_type sub_end; + DerefHolder> item; FilterFunc filter_func; + void inc_sub_iter() { + ++this->sub_iter; + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); + } + } + // increment until the iterator points to is true on the // predicate. Called by constructor and operator++ void skip_failures() { while (this->sub_iter != this->sub_end - && !this->filter_func(*this->sub_iter)) { - ++this->sub_iter; + && !this->filter_func(this->item.get())) { + this->inc_sub_iter(); } } @@ -68,15 +76,18 @@ namespace iter { sub_end{end}, filter_func(filter_func) { + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); + } this->skip_failures(); } iterator_deref operator*() { - return *this->sub_iter; + return this->item.pull(); } Iterator& operator++() { - ++this->sub_iter; + this->inc_sub_iter(); this->skip_failures(); return *this; } From fe608c7b2a86c1bd78befaabdb69ad4ccce13180 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 11:14:55 -0500 Subject: [PATCH 0955/1866] builds mixed test --- catchtest/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index 0a8c1e35..80dc8d25 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -45,6 +45,7 @@ progs = Split( zip_longest iteratoriterator + mixed ''' ) From c5ae80c487c362e6d3f0891fe4ae1b606c68b39d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 11:18:46 -0500 Subject: [PATCH 0956/1866] moves rather than copies iterators --- imap.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imap.hpp b/imap.hpp index 9df55a1a..daa8cdb5 100644 --- a/imap.hpp +++ b/imap.hpp @@ -98,9 +98,9 @@ namespace iter { ZippedIterType zipiter; public: - Iterator(MapFunc map_func, ZippedIterType zipiter) : + Iterator(MapFunc map_func, ZippedIterType&& in_zipiter) : map_func(map_func), - zipiter(zipiter) + zipiter(std::move(in_zipiter)) { } IMapIterDeref operator*() { From 4bc52a9dfe1a5c70962268ef126096b02a8588cc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 11:19:03 -0500 Subject: [PATCH 0957/1866] moves rather than copies iterators --- zip.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zip.hpp b/zip.hpp index 64b3f087..285146a8 100644 --- a/zip.hpp +++ b/zip.hpp @@ -48,9 +48,9 @@ namespace 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&& it, RestIter&& rest) + : iter{std::move(it)}, + rest_iter{std::move(rest)} { } Iterator& operator++() { From 4e6a8433ee675f36a557395869b87323ce97a7f1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 11:33:23 -0500 Subject: [PATCH 0958/1866] moves iterators rather than copies --- accumulate.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index 8df2e409..06f22168 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -35,7 +35,7 @@ namespace iter { template friend Accumulator, AF> accumulate( std::initializer_list, AF); - + // AccumVal must be default constructible using AccumVal = typename std::remove_reference< @@ -61,11 +61,11 @@ namespace iter { AccumulateFunc accumulate_func; AccumVal acc_val; public: - Iterator (iterator_type iter, - iterator_type end, + Iterator (iterator_type&& iter, + iterator_type&& end, AccumulateFunc accumulate_func) - : sub_iter{iter}, - sub_end{end}, + : sub_iter{std::move(iter)}, + sub_end{std::move(end)}, accumulate_func(accumulate_func), // only get first value if not an end iterator acc_val(!(iter != end) ? AccumVal{} : *iter) From ea211ad418e8f81f2be0cadd12b0262e2ceac835 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 11:35:54 -0500 Subject: [PATCH 0959/1866] moves iterators rather than copies --- chain.hpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/chain.hpp b/chain.hpp index 5130dc56..a05a39da 100644 --- a/chain.hpp +++ b/chain.hpp @@ -50,12 +50,12 @@ namespace 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}, + Iterator(iterator_type&& s_begin, + iterator_type&& s_end, + RestIter&& rest_iter) + : sub_iter{std::move(s_begin)}, + sub_end{std::move(s_end)}, + rest_iter{std::move(rest_iter)}, at_end{!(sub_iter != sub_end)} { } @@ -211,10 +211,10 @@ namespace iter { } public: - Iterator(iterator_type top_iter, - iterator_type top_end) - : top_level_iter{top_iter}, - top_level_end{top_end}, + Iterator(iterator_type&& top_iter, + iterator_type&& top_end) + : top_level_iter{std::move(top_iter)}, + top_level_end{std::move(top_end)}, sub_iter_p{!(top_iter != top_end) ? // iter == end ? nullptr : new SubIter{std::begin(*top_iter)}}, sub_end_p{!(top_iter != top_end) ? // iter == end ? From 4f052c3f58f479955cf17b610a36c2c7f5db36b1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 11:38:06 -0500 Subject: [PATCH 0960/1866] moves iterators rather than copies --- compress.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compress.hpp b/compress.hpp index 4dfab7a8..29318fe3 100644 --- a/compress.hpp +++ b/compress.hpp @@ -89,14 +89,14 @@ namespace iter { } public: - Iterator(iterator_type cont_iter, - iterator_type cont_end, - selector_iter_type sel_iter, - selector_iter_type sel_end) - : sub_iter{cont_iter}, - sub_end{cont_end}, - selector_iter{sel_iter}, - selector_end{sel_end} + Iterator(iterator_type&& cont_iter, + iterator_type&& cont_end, + selector_iter_type&& sel_iter, + selector_iter_type&& sel_end) + : sub_iter{std::move(cont_iter)}, + sub_end{std::move(cont_end)}, + selector_iter{std::move(sel_iter)}, + selector_end{std::move(sel_end)} { this->skip_failures(); } From 86a3d94f23567b16dbabde7a36a0c53059d2d348 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 11:39:25 -0500 Subject: [PATCH 0961/1866] moves end, copies begin --- cycle.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cycle.hpp b/cycle.hpp index 484fc922..d63403ba 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -43,11 +43,11 @@ namespace iter { iterator_type begin; iterator_type end; public: - Iterator (iterator_type iter, - iterator_type end) + Iterator (const iterator_type& iter, + iterator_type&& end) : sub_iter{iter}, begin{iter}, - end{end} + end{std::move(end)} { } iterator_deref operator*() { From bf33f346314b14d2ddcc1f85badbb8476e512c83 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 11:40:42 -0500 Subject: [PATCH 0962/1866] moves iterators rather than copies --- dropwhile.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index 169aa305..55c10fc6 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -56,11 +56,11 @@ namespace iter { } public: - Iterator (iterator_type iter, - iterator_type end, + Iterator(iterator_type&& iter, + iterator_type&& end, FilterFunc filter_func) - : sub_iter{iter}, - sub_end{end}, + : sub_iter{std::move(iter)}, + sub_end{std::move(end)}, filter_func(filter_func) { this->skip_passes(); From b2e4e224b236142ffc1e271bb8f4ce1edf469424 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 11:41:12 -0500 Subject: [PATCH 0963/1866] moves iterators rather than copies --- enumerate.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index cba785f5..c9b7ee76 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -71,8 +71,8 @@ namespace iter { iterator_type sub_iter; std::size_t index; public: - Iterator(const iterator_type& si) - : sub_iter{si}, + Iterator(iterator_type&& si) + : sub_iter{std::move(si)}, index{0} { } From 13874b6e4bb5fe6e11da4c8ac137f09ed361d4bd Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 11:42:39 -0500 Subject: [PATCH 0964/1866] moves iterators rather than copies --- groupby.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index 42768202..a78cc69a 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -66,11 +66,11 @@ namespace iter { KeyFunc key_func; public: - Iterator (iterator_type si, - iterator_type end, + Iterator(iterator_type&& si, + iterator_type&& end, KeyFunc key_func) - : sub_iter{si}, - sub_end{end}, + : sub_iter{std::move(si)}, + sub_end{std::move(end)}, key_func(key_func) { } From 9c5ed817ebf0f31fa88a5e3d380d90d9387f3e3d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 11:43:25 -0500 Subject: [PATCH 0965/1866] eliminates extra copies --- grouper.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/grouper.hpp b/grouper.hpp index 3cb69fe1..c96a9f80 100644 --- a/grouper.hpp +++ b/grouper.hpp @@ -67,8 +67,8 @@ namespace iter { } public: - Iterator(iterator_type in_iter, - iterator_type in_end, + Iterator(iterator_type&& in_iter, + iterator_type&& in_end, std::size_t s) : sub_iter{std::move(in_iter)}, sub_end{std::move(in_end)}, From 707f0aab6ce01a9969b03881fd0e5d26dac33ef6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 11:44:52 -0500 Subject: [PATCH 0966/1866] eliminates extra copies --- permutations.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/permutations.hpp b/permutations.hpp index c16a8f4e..547b6aef 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -40,8 +40,8 @@ namespace iter { int steps{}; public: - Iterator(iterator_type sub_iter, - iterator_type sub_end) + Iterator(iterator_type&& sub_iter, + iterator_type&& sub_end) : steps{ sub_iter != sub_end ? 0 : COMPLETE } { // done like this instead of using vector ctor with From 9e8aeaaeea1753539d3fcabfef7bcf21ccc41385 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 11:46:33 -0500 Subject: [PATCH 0967/1866] removes extra moves --- product.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/product.hpp b/product.hpp index aaf0f42d..2866406f 100644 --- a/product.hpp +++ b/product.hpp @@ -53,9 +53,9 @@ namespace iter { RestIter rest_end; public: constexpr static const bool is_base_iter = false; - Iterator(iterator_type it, - const RestIter& rest, - const RestIter& in_rest_end) + Iterator(const iterator_type& it, + RestIter&& rest, + RestIter&& in_rest_end) : iter{it}, begin{it}, rest_iter{rest}, From a3e11c95d44d1fb5314d8e9d442104079858e937 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 11:48:06 -0500 Subject: [PATCH 0968/1866] moves iterators rather than copies --- reversed.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reversed.hpp b/reversed.hpp index 9d580ec5..b9427f72 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -32,8 +32,8 @@ namespace iter { private: reverse_iterator_type sub_iter; public: - Iterator (reverse_iterator_type iter) - : sub_iter{iter} + Iterator (reverse_iterator_type&& iter) + : sub_iter{std::move(iter)} { } reverse_iterator_deref operator*() { From bca97a5fee82fea7407df4ed335c2d440ca1cdb2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 11:49:13 -0500 Subject: [PATCH 0969/1866] moves iterators rather than copies --- slice.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/slice.hpp b/slice.hpp index d04f863b..f31e164b 100644 --- a/slice.hpp +++ b/slice.hpp @@ -54,8 +54,8 @@ namespace iter { DifferenceType step; public: - Iterator (iterator_type si, - iterator_type se, + Iterator (iterator_type&& si, + iterator_type&& se, DifferenceType start, DifferenceType stop, DifferenceType step) From b088968d91e1588df9bf0251b18b11fc3e8e2d4d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 11:51:32 -0500 Subject: [PATCH 0970/1866] eliminates extra iterator copies --- sliding_window.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sliding_window.hpp b/sliding_window.hpp index 94cc66e7..7780f183 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -48,13 +48,14 @@ namespace iter { DerefVec window; public: - Iterator(const iterator_type& in_iter, + Iterator(iterator_type&& in_iter, const iterator_type& in_end, std::size_t window_sz) - : sub_iter(in_iter) + : sub_iter(std::move(in_iter)) { std::size_t i{0}; - while (i < window_sz && this->sub_iter != in_end) { + while (i < window_sz + && this->sub_iter != in_end) { this->window.get().push_back(this->sub_iter); ++i; if (i != window_sz) ++this->sub_iter; From 41380f3299d406ce4e0d4506d34c5a0ee7c9f9e3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 11:52:55 -0500 Subject: [PATCH 0971/1866] moves iterators rather than copies --- takewhile.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/takewhile.hpp b/takewhile.hpp index 12eb4368..2c851db4 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -58,11 +58,11 @@ namespace iter { } public: - Iterator(iterator_type iter, - iterator_type end, + Iterator(iterator_type&& iter, + iterator_type&& end, FilterFunc filter_func) - : sub_iter{iter}, - sub_end{end}, + : sub_iter{std::move(iter)}, + sub_end{std::move(end)}, filter_func(filter_func) { if (this->sub_iter != this->sub_end) { From 2d1566cdf8ee7803a02c45328d75b696e8c814de Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 11:55:18 -0500 Subject: [PATCH 0972/1866] moves iterators rather than copies --- zip_longest.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/zip_longest.hpp b/zip_longest.hpp index cc6705b9..044a9191 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -57,12 +57,12 @@ namespace iter { public: Iterator( - iterator_type it, - iterator_type in_end, - const RestIter& rest) - : iter{it}, - end{in_end}, - rest_iter{rest} + iterator_type&& it, + iterator_type&& in_end, + RestIter&& rest) + : iter{std::move(it)}, + end{std::move(in_end)}, + rest_iter{std::move(rest)} { } Iterator& operator++() { From 2552d4bdc4ae3e6fffe787be5620dfb93a355025 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 18:10:01 -0500 Subject: [PATCH 0973/1866] adds double-deref test for dropwhile --- catchtest/test_mixed.cpp | 45 +++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/catchtest/test_mixed.cpp b/catchtest/test_mixed.cpp index d3618348..f78b7fe9 100644 --- a/catchtest/test_mixed.cpp +++ b/catchtest/test_mixed.cpp @@ -1,17 +1,13 @@ // mixing different itertools, there is nothing called iter::mixed() -#include "imap.hpp" -#include "filter.hpp" +#include "itertools.hpp" #include "catch.hpp" #include #include -using iter::filter; -using iter::imap; - class MyUnMovable { int val; public: @@ -42,13 +38,7 @@ class MyUnMovable { } }; -TEST_CASE("imap and filter where imap Functor modifies its sequence", - "[imap][filter]") { - - // source data - std::array arr = {{{41}, {42}, {43}}}; - - // some transformations +namespace { auto inc_ten = [](MyUnMovable& el) -> MyUnMovable& { int va = el.get_val(); el.set_val(va + 10); @@ -59,6 +49,14 @@ TEST_CASE("imap and filter where imap Functor modifies its sequence", el.set_val(va - 10); return el; }; +} + +TEST_CASE("filtering doesn't dereference multiple times", "[imap][filter]") { + using iter::filter; + using iter::imap; + + // source data + std::array arr = {{{41}, {42}, {43}}}; auto transformed1 = imap(inc_ten, arr); auto filtered = filter([](const MyUnMovable& el) { @@ -80,3 +78,26 @@ TEST_CASE("imap and filter where imap Functor modifies its sequence", constexpr std::array arrc = {{{41}, {52}, {43}}}; REQUIRE( arr == arrc ); } + +TEST_CASE("dropwhile doesn't dereference multiple times", "[imap][dropwhile]"){ + using iter::imap; + using iter::dropwhile; + // source data + std::array arr = {{{41}, {42}, {43}}}; + + auto transformed1 = imap(inc_ten, arr); + auto filtered = dropwhile([](const MyUnMovable& el) { + return 52 != el.get_val(); + }, transformed1); + auto transformed2 = imap(dec_ten, filtered); + + std::vector v; + for (auto&& el : transformed2) { + v.push_back(el.get_val()); + } + + std::vector vc = {42, 43}; + + constexpr std::array arrc = {{{51}, {42}, {43}}}; + REQUIRE( arr == arrc ); +} From 019d30e2f6fb85220d693464024c865cc65a1388 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 18:10:36 -0500 Subject: [PATCH 0974/1866] removes include of wrap_iter --- itertools.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/itertools.hpp b/itertools.hpp index 55039902..8e84eed3 100644 --- a/itertools.hpp +++ b/itertools.hpp @@ -27,7 +27,6 @@ #include "takewhile.hpp" #include "unique_everseen.hpp" #include "unique_justseen.hpp" -#include "wrap_iter.hpp" #include "zip.hpp" #include "zip_longest.hpp" From e39e1f5c3529a503a6194ffb8cca8b0da6a3f80a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 19:33:06 -0500 Subject: [PATCH 0975/1866] tests dropwhile for multiple dereferencing --- catchtest/test_mixed.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/catchtest/test_mixed.cpp b/catchtest/test_mixed.cpp index f78b7fe9..f98fc0c2 100644 --- a/catchtest/test_mixed.cpp +++ b/catchtest/test_mixed.cpp @@ -98,6 +98,8 @@ TEST_CASE("dropwhile doesn't dereference multiple times", "[imap][dropwhile]"){ std::vector vc = {42, 43}; - constexpr std::array arrc = {{{51}, {42}, {43}}}; - REQUIRE( arr == arrc ); + std::vector vsc = {51, 42, 43}; + auto get_vals = imap([](const MyUnMovable& mv){return mv.get_val();}, arr); + std::vector vs(std::begin(get_vals), std::end(get_vals)); + REQUIRE( vs == vsc ); } From a7d4e6dac09a776e056e158535e1d03f62b6b569 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 19:33:27 -0500 Subject: [PATCH 0976/1866] removes multiple dereference from dropwhile --- dropwhile.hpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index 55c10fc6..3e905170 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -45,13 +45,21 @@ namespace iter { private: iterator_type sub_iter; iterator_type sub_end; + DerefHolder> item; FilterFunc filter_func; + void inc_sub_iter() { + ++this->sub_iter; + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); + } + } + // skip all values for which the predicate is true void skip_passes() { while (this->sub_iter != this->sub_end - && this->filter_func(*this->sub_iter)) { - ++this->sub_iter; + && this->filter_func(this->item.get())) { + this->inc_sub_iter(); } } @@ -63,15 +71,18 @@ namespace iter { sub_end{std::move(end)}, filter_func(filter_func) { + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); + } this->skip_passes(); } iterator_deref operator*() { - return *this->sub_iter; + return this->item.pull(); } Iterator& operator++() { - ++this->sub_iter; + this->inc_sub_iter(); return *this; } From c8fa12aa7ebf4cac40988c6d2baa3f4a3a1aa6b6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 19:53:41 -0500 Subject: [PATCH 0977/1866] tests filter iterator assignment --- catchtest/test_filter.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/catchtest/test_filter.cpp b/catchtest/test_filter.cpp index eb21b2c2..985e38e2 100644 --- a/catchtest/test_filter.cpp +++ b/catchtest/test_filter.cpp @@ -53,6 +53,14 @@ TEST_CASE("filter: handles different functor types", "[filter]") { } } +TEST_CASE("filter: iterator with lambda can be assigned", "[filter]") { + Vec ns{}; + auto ltf = [](int i) {return i < 5;}; + auto f = filter(ltf, ns); + auto it = std::begin(f); + it = std::begin(f); +} + TEST_CASE("filter: using identity", "[filter]") { Vec ns{0, 1, 2, 0, 3, 0, 0, 0, 4, 5, 0}; auto f = filter(ns); From 32495f9b2a7ead95707c146c8d252b117659ae25 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 19:54:07 -0500 Subject: [PATCH 0978/1866] uses pointer to FuncType for iterator operator= Without this, Filter::Iterator::operator= fails with lambdas since lambdas can't be assigned (apparently). --- filter.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/filter.hpp b/filter.hpp index 54947c5d..b9136874 100644 --- a/filter.hpp +++ b/filter.hpp @@ -50,7 +50,7 @@ namespace iter { iterator_type sub_iter; iterator_type sub_end; DerefHolder> item; - FilterFunc filter_func; + FilterFunc *filter_func; void inc_sub_iter() { ++this->sub_iter; @@ -63,7 +63,7 @@ namespace iter { // predicate. Called by constructor and operator++ void skip_failures() { while (this->sub_iter != this->sub_end - && !this->filter_func(this->item.get())) { + && !(*this->filter_func)(this->item.get())) { this->inc_sub_iter(); } } @@ -71,10 +71,10 @@ namespace iter { public: Iterator (iterator_type iter, iterator_type end, - FilterFunc filter_func) + FilterFunc& filter_func) : sub_iter{iter}, sub_end{end}, - filter_func(filter_func) + filter_func(&filter_func) { if (this->sub_iter != this->sub_end) { this->item.reset(*this->sub_iter); From 3f137ced732328c7a6d832bc1fb2e14bc7566846 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 19:56:03 -0500 Subject: [PATCH 0979/1866] FilterFunc * for dropwhile iterator --- dropwhile.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index 3e905170..a89e5a81 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -46,7 +46,7 @@ namespace iter { iterator_type sub_iter; iterator_type sub_end; DerefHolder> item; - FilterFunc filter_func; + FilterFunc *filter_func; void inc_sub_iter() { ++this->sub_iter; @@ -58,7 +58,7 @@ namespace iter { // skip all values for which the predicate is true void skip_passes() { while (this->sub_iter != this->sub_end - && this->filter_func(this->item.get())) { + && (*this->filter_func)(this->item.get())) { this->inc_sub_iter(); } } @@ -66,10 +66,10 @@ namespace iter { public: Iterator(iterator_type&& iter, iterator_type&& end, - FilterFunc filter_func) + FilterFunc& filter_func) : sub_iter{std::move(iter)}, sub_end{std::move(end)}, - filter_func(filter_func) + filter_func(&filter_func) { if (this->sub_iter != this->sub_end) { this->item.reset(*this->sub_iter); From 90275c1cc8e9011b07094756e06191c9cd51760c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 19:56:48 -0500 Subject: [PATCH 0980/1866] takewhile uses derefholder --- takewhile.hpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/takewhile.hpp b/takewhile.hpp index 2c851db4..bbf0a21d 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -48,11 +48,19 @@ namespace iter { private: iterator_type sub_iter; iterator_type sub_end; + DerefHolder> item; FilterFunc filter_func; + void inc_sub_iter() { + ++this->sub_iter; + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); + } + } + void check_current() { if (this->sub_iter != this->sub_end - && !this->filter_func(*this->sub_iter)) { + && !this->filter_func(this->item.get())) { this->sub_iter = this->sub_end; } } @@ -66,17 +74,17 @@ namespace iter { filter_func(filter_func) { if (this->sub_iter != this->sub_end) { - // only do the check if not already at the end - this->check_current(); + this->item.reset(*this->sub_iter); } + this->check_current(); } iterator_deref operator*() { - return *this->sub_iter; + return this->item.pull(); } Iterator& operator++() { - ++this->sub_iter; + this->inc_sub_iter(); this->check_current(); return *this; } From 4c689e6948d5d3d5461ce7aa7b232ecc48bedfd5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 19:58:25 -0500 Subject: [PATCH 0981/1866] imap iterator uses MapFunc * --- imap.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/imap.hpp b/imap.hpp index daa8cdb5..79a8deae 100644 --- a/imap.hpp +++ b/imap.hpp @@ -94,18 +94,18 @@ namespace iter { typename std::remove_reference::type > { private: - MapFunc map_func; + MapFunc *map_func; ZippedIterType zipiter; public: - Iterator(MapFunc map_func, ZippedIterType&& in_zipiter) : - map_func(map_func), + Iterator(MapFunc& map_func, ZippedIterType&& in_zipiter) : + map_func(&map_func), zipiter(std::move(in_zipiter)) { } IMapIterDeref operator*() { return detail::call_with_tuple( - this->map_func, *(this->zipiter)); + *this->map_func, *(this->zipiter)); } Iterator& operator++() { From fb3518123500d67248399241c32a8e92e5c5c020 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 19:58:49 -0500 Subject: [PATCH 0982/1866] takewhile iterator uses FiterFunc* --- takewhile.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/takewhile.hpp b/takewhile.hpp index bbf0a21d..bd518c32 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -49,7 +49,7 @@ namespace iter { iterator_type sub_iter; iterator_type sub_end; DerefHolder> item; - FilterFunc filter_func; + FilterFunc *filter_func; void inc_sub_iter() { ++this->sub_iter; @@ -60,7 +60,7 @@ namespace iter { void check_current() { if (this->sub_iter != this->sub_end - && !this->filter_func(this->item.get())) { + && !(*this->filter_func)(this->item.get())) { this->sub_iter = this->sub_end; } } @@ -68,10 +68,10 @@ namespace iter { public: Iterator(iterator_type&& iter, iterator_type&& end, - FilterFunc filter_func) + FilterFunc& filter_func) : sub_iter{std::move(iter)}, sub_end{std::move(end)}, - filter_func(filter_func) + filter_func(&filter_func) { if (this->sub_iter != this->sub_end) { this->item.reset(*this->sub_iter); From 70c2e380db3330f1847d7c52dfb6d327db717b2b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 19:59:11 -0500 Subject: [PATCH 0983/1866] tests takewhile for double-deref --- catchtest/test_mixed.cpp | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/catchtest/test_mixed.cpp b/catchtest/test_mixed.cpp index f98fc0c2..f0ed106e 100644 --- a/catchtest/test_mixed.cpp +++ b/catchtest/test_mixed.cpp @@ -82,7 +82,7 @@ TEST_CASE("filtering doesn't dereference multiple times", "[imap][filter]") { TEST_CASE("dropwhile doesn't dereference multiple times", "[imap][dropwhile]"){ using iter::imap; using iter::dropwhile; - // source data + std::array arr = {{{41}, {42}, {43}}}; auto transformed1 = imap(inc_ten, arr); @@ -103,3 +103,28 @@ TEST_CASE("dropwhile doesn't dereference multiple times", "[imap][dropwhile]"){ std::vector vs(std::begin(get_vals), std::end(get_vals)); REQUIRE( vs == vsc ); } + +TEST_CASE("takewhile doesn't dereference multiple times", "[imap][takewhile]"){ + using iter::imap; + using iter::takewhile; + + std::array arr = {{{41}, {42}, {43}}}; + + auto transformed1 = imap(inc_ten, arr); + auto filtered = takewhile([](const MyUnMovable& el) { + return 53 != el.get_val(); + }, transformed1); + auto transformed2 = imap(dec_ten, filtered); + + std::vector v; + for (auto&& el : transformed2) { + v.push_back(el.get_val()); + } + + std::vector vc = {41, 42}; + + std::vector vsc = {41, 42, 53}; + auto get_vals = imap([](const MyUnMovable& mv){return mv.get_val();}, arr); + std::vector vs(std::begin(get_vals), std::end(get_vals)); + REQUIRE( vs == vsc ); +} From 72a2ed8bd5fe2a6a194f290948d04cee57f63e08 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 19:59:26 -0500 Subject: [PATCH 0984/1866] simplifies DerefHolder --- iterbase.hpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/iterbase.hpp b/iterbase.hpp index aacd2246..3b111040 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -134,10 +134,6 @@ namespace iter { std::unique_ptr item_p; public: - explicit DerefHolder() - : item_p{nullptr} - { } - DerefHolder(const DerefHolder& other) : item_p{new TPlain(*other.item_p)} { } @@ -176,12 +172,9 @@ namespace iter { private: static_assert(std::is_lvalue_reference::value, "lvalue specialization handling non-lvalue-ref type"); - typename std::remove_reference::type *item_p; - public: - explicit DerefHolder() - : item_p{nullptr} - { } + typename std::remove_reference::type *item_p =nullptr; + public: T get() { return *this->item_p; } From 14c5246a13e6a4fdcec561d08e3aca1ba9430de6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 20:02:42 -0500 Subject: [PATCH 0985/1866] uses default argument to eliminate count overload --- count.hpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/count.hpp b/count.hpp index e0bc7cd0..c4e62087 100644 --- a/count.hpp +++ b/count.hpp @@ -7,13 +7,6 @@ namespace iter { - using DefaultRangeType = long; - - auto count() -> decltype(range(DefaultRangeType(0), DefaultRangeType(0))) { - return range(DefaultRangeType(0), - std::numeric_limits::max()); - } - template auto count(T start, T step) -> decltype(range(start, start, start)) { // if step is < 0, set the stop to numeric min, otherwise numeric max @@ -22,8 +15,8 @@ namespace iter { return range(start, stop, step); } - template - auto count(T start) -> decltype(range(start, start)) { + template + auto count(T start =T(0)) -> decltype(range(start, start)) { return count(start, T(1)); } } From cfd592f1993ecde77b3f5966963fc3b2260da31d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 17 Feb 2015 23:59:29 -0500 Subject: [PATCH 0986/1866] checks for null when copying DerefHolder --- iterbase.hpp | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/iterbase.hpp b/iterbase.hpp index 3b111040..58d6ee96 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -123,6 +123,16 @@ namespace iter { : std::integral_constant::value && are_same::value> { }; + // DerefHolder holds the value gotten from an iterator dereference + // if the iterate dereferences to an lvalue references, a pointer to the + // element is stored + // if it does not, a value is stored instead + // get() returns a reference to the held item in either case + // pull() should be used when the item is being "pulled out" of the + // DerefHolder. after pull() is called, neither it nor get() can be + // safely called after + // reset() replaces the currently held item and may be called after pull() + template class DerefHolder { private: @@ -135,11 +145,12 @@ namespace iter { public: DerefHolder(const DerefHolder& other) - : item_p{new TPlain(*other.item_p)} + : item_p{other.item_p ? new TPlain(*other.item_p) : nullptr} { } DerefHolder& operator=(const DerefHolder& other) { - this->item_p.reset(new TPlain(*other.item_p)); + this->item_p.reset(other.item_p + ? new TPlain(*other.item_p) : nullptr); return *this; } @@ -152,14 +163,18 @@ namespace iter { } T pull() { - return std::move(*item_p); // NOTE should I reset the unique_ptr to nullptr here // since its held item is now invalid anyway? + return std::move(*item_p); } void reset(T&& item) { item_p.reset(new TPlain(std::move(item))); } + + explicit operator bool() const { + return this->item_p; + } }; @@ -186,6 +201,10 @@ namespace iter { void reset(T item) { this->item_p = &item; } + + explicit operator bool() const { + return this->item_p != nullptr; + } }; From 8161f3902519486b5c116bb96e31cca8f56279e4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 18 Feb 2015 00:23:11 -0500 Subject: [PATCH 0987/1866] 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 0988/1866] 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 0989/1866] 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 0990/1866] 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 2640ca1b544c3560f94c7e3669bbc5dd81a1fb5e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 18 Feb 2015 00:44:37 -0500 Subject: [PATCH 0991/1866] explicitly default default ctor for DerefHolder --- iterbase.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iterbase.hpp b/iterbase.hpp index 58d6ee96..1f962d84 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -144,6 +144,8 @@ 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} { } @@ -190,6 +192,8 @@ 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 0992/1866] 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 eb990a7c88ed2015dab12b4164ced8c2b4c1a8a4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 18 Feb 2015 11:10:58 -0500 Subject: [PATCH 0993/1866] forwards elements in call_with_tuple --- imap.hpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/imap.hpp b/imap.hpp index 79a8deae..168cfd99 100644 --- a/imap.hpp +++ b/imap.hpp @@ -5,6 +5,7 @@ #include #include +#include namespace iter { @@ -17,14 +18,21 @@ namespace iter { -> decltype(Expander::call( std::forward(f), std::forward(tup), - std::get(tup), + std::forward< + typename std::tuple_element::type>::type>( + std::get(tup)), std::forward(args)...)) { // recurse return Expander::call( std::forward(f), std::forward(tup), - std::get(tup), // pull out one element + // pull out one element + std::forward< + typename std::tuple_element::type>::type>( + std::get(tup)), std::forward(args)...); // everything already expanded } }; From 3d971c9b5434fdc5ed1cf02f0e97adfbd69185f6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 21 Feb 2015 15:49:00 -0500 Subject: [PATCH 0994/1866] adds a helper to throw on double deref auto it = std::begin(ii); *it; // fine ++it; *it; // fine *it; // no ++, throws --- catchtest/helpers.hpp | 77 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/catchtest/helpers.hpp b/catchtest/helpers.hpp index d3dacfa6..7c0c1eaa 100644 --- a/catchtest/helpers.hpp +++ b/catchtest/helpers.hpp @@ -2,6 +2,8 @@ #define TEST_HELPER_H_ #include +#include +#include namespace itertest { @@ -25,6 +27,57 @@ class SolidInt { SolidInt(SolidInt&&) = delete; }; +namespace { + struct DoubleDereferenceError : std::exception { + const char *what() const noexcept override { + return "Iterator dereferenced twice without increment"; + } + }; + + // this class's iterator will throw if it's dereference twice without + // an increment in between + class InputIterable { + public: + class Iterator { + private: + int i; + bool was_incremented = true; + + public: + Iterator(int n) + : i{n} + { } + + Iterator& operator++() { + ++this->i; + this->was_incremented = true; + return *this; + } + + int operator*() { + if (!this->was_incremented) { + throw DoubleDereferenceError{}; + } + this->was_incremented = false; + return this->i; + } + + bool operator!=(const Iterator& other) const { + return this->i != other.i; + } + }; + + Iterator begin() { + return {0}; + } + + Iterator end() { + return {3}; + } + }; +} + + // BasicIterable provides a minimal forward iterator // operator++(), operator!=(const BasicIterable&), operator*() @@ -117,6 +170,30 @@ class BasicIterable { } }; + +// gcc CWG 1558 +template +struct void_t_help { + using type = void; +}; +template + +using void_t = typename void_t_help::type; + +template +struct IsIterator : std::false_type { }; + +template +struct IsIterator ())), // copyctor + decltype(std::declval() = std::declval()), // copy = + decltype(*std::declval()), // operator* + decltype(++std::declval()), // prefix ++ + decltype(std::declval()++), // postfix ++ + decltype(std::declval() != std::declval()), // != + decltype(std::declval() == std::declval()) // == + >> : std::true_type { }; + } #endif From 6a62b40f7f1035901f3b822e6de76355c4dcfc46 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 21 Feb 2015 15:50:06 -0500 Subject: [PATCH 0995/1866] tests that groupby doesn't double-dereference --- catchtest/test_groupby.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/catchtest/test_groupby.cpp b/catchtest/test_groupby.cpp index 6b67f16d..f94c2f98 100644 --- a/catchtest/test_groupby.cpp +++ b/catchtest/test_groupby.cpp @@ -152,3 +152,12 @@ TEST_CASE("groupby: inner iterator (group) not used", "[groupby]") { std::vector kc = {2, 3, 5}; REQUIRE( keys == kc ); } + +TEST_CASE("groupby: doesn't double dereference", "[groupby]") { + itertest::InputIterable seq; + for (auto&& kg : groupby(seq)) { + for (auto&& e : kg.second) { + (void)e; + } + } +} From 059d9eab1904f386dab561ecab1912c9d076912c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 21 Feb 2015 15:55:37 -0500 Subject: [PATCH 0996/1866] stretches out inputiterable length --- catchtest/helpers.hpp | 2 +- groupby.hpp | 39 ++++++++++++++++++++++++--------------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/catchtest/helpers.hpp b/catchtest/helpers.hpp index 7c0c1eaa..29203304 100644 --- a/catchtest/helpers.hpp +++ b/catchtest/helpers.hpp @@ -72,7 +72,7 @@ namespace { } Iterator end() { - return {3}; + return {5}; } }; } diff --git a/groupby.hpp b/groupby.hpp index a78cc69a..0e754c15 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -61,23 +61,28 @@ namespace iter { { private: iterator_type sub_iter; - iterator_type sub_iter_peek; iterator_type sub_end; - KeyFunc key_func; + DerefHolder> item; + KeyFunc *key_func; public: Iterator(iterator_type&& si, iterator_type&& end, - KeyFunc key_func) + KeyFunc& key_func) : sub_iter{std::move(si)}, sub_end{std::move(end)}, - key_func(key_func) - { } + key_func(&key_func) + { + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); + } + } KeyGroupPair operator*() { + // FIXME double deref return { - this->key_func(*this->sub_iter), - Group{*this, this->key_func(*this->sub_iter)} + (*this->key_func)(this->item.get()), + Group{*this, (*this->key_func)(this->item.get())} }; } @@ -102,6 +107,9 @@ namespace iter { void increment_iterator() { if (this->sub_iter != this->sub_end) { ++this->sub_iter; + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); + } } } @@ -109,12 +117,13 @@ namespace iter { return !(this->sub_iter != this->sub_end); } - iterator_deref current() { - return *this->sub_iter; + iterator_deref pull() { + return this->item.pull(); } + // FIXME double deref. Two deref holders? key_func_ret next_key() { - return this->key_func(*this->sub_iter); + return (*this->key_func)(this->item.get()); } }; @@ -170,18 +179,18 @@ namespace iter { iterator_traits_deref> { private: - key_func_ret key; + typename std::remove_reference::type *key; Group *group_p; bool not_at_end() { return !this->group_p->owner.exhausted()&& - this->group_p->owner.next_key() == this->key; + this->group_p->owner.next_key() == *this->key; } public: GroupIterator(Group *in_group_p, - key_func_ret key) - : key{key}, + key_func_ret& key) + : key{&key}, group_p{in_group_p} { } @@ -209,7 +218,7 @@ namespace iter { } iterator_deref operator*() { - return this->group_p->owner.current(); + return this->group_p->owner.pull(); } }; From 7f4f0e1bdd0c8946e2c4457fd2729a3bbb10af96 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 21 Feb 2015 15:55:58 -0500 Subject: [PATCH 0997/1866] makes groups of more that one element --- catchtest/test_groupby.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/catchtest/test_groupby.cpp b/catchtest/test_groupby.cpp index f94c2f98..943f99dc 100644 --- a/catchtest/test_groupby.cpp +++ b/catchtest/test_groupby.cpp @@ -155,7 +155,7 @@ TEST_CASE("groupby: inner iterator (group) not used", "[groupby]") { TEST_CASE("groupby: doesn't double dereference", "[groupby]") { itertest::InputIterable seq; - for (auto&& kg : groupby(seq)) { + for (auto&& kg : groupby(seq, [](int i){return i < 3;})) { for (auto&& e : kg.second) { (void)e; } From 3ed735ffb04a719f0efd75ed56bf1c4854b20290 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 21 Feb 2015 17:17:09 -0500 Subject: [PATCH 0998/1866] makes product iter assignable by removing a const data member --- product.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/product.hpp b/product.hpp index 2866406f..44210a51 100644 --- a/product.hpp +++ b/product.hpp @@ -47,7 +47,7 @@ namespace iter { typename Productor::Iterator; iterator_type iter; - const iterator_type begin; + iterator_type begin; RestIter rest_iter; RestIter rest_end; From c319227ec542468cd746d14ee986e113f6cad62b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 21 Feb 2015 20:11:24 -0500 Subject: [PATCH 0999/1866] tests IsIterator tests --- catchtest/test_helpers.cpp | 85 +++++++++++++++++++++++++++++++++----- 1 file changed, 75 insertions(+), 10 deletions(-) diff --git a/catchtest/test_helpers.cpp b/catchtest/test_helpers.cpp index f3c59813..22d0a858 100644 --- a/catchtest/test_helpers.cpp +++ b/catchtest/test_helpers.cpp @@ -1,17 +1,82 @@ -#include "helpers.hpp" #include #include "catch.hpp" +#include "helpers.hpp" using itertest::SolidInt; +using itertest::IsIterator; + +namespace { + +class ValidIter { + private: + int i; + public: + ValidIter& operator++(); // prefix + ValidIter operator++(int); // postfix + bool operator==(const ValidIter&) const; + bool operator!=(const ValidIter&) const; + int operator*(); +}; + +} + +TEST_CASE("IsIterator fails when missing prefix ++", "[helpers]") { + struct InvalidIter : ValidIter { + InvalidIter& operator++() = delete; + }; + + REQUIRE( !IsIterator::value ); +} + +TEST_CASE("IsIterator fails when missing postfix ++", "[helpers]") { + struct InvalidIter : ValidIter { + InvalidIter operator++(int) = delete; + }; + + REQUIRE( !IsIterator::value ); +} + +TEST_CASE("IsIterator fails when missing ==", "[helpers]") { + struct InvalidIter : ValidIter { + bool operator==(const InvalidIter&) const = delete; + }; + + REQUIRE( !IsIterator::value ); +} + +TEST_CASE("IsIterator fails when missing !=", "[helpers]") { + struct InvalidIter : ValidIter { + bool operator!=(const InvalidIter&) const = delete; + }; + + REQUIRE( !IsIterator::value ); +} + +TEST_CASE("IsIterator fails when missing *", "[helpers]") { + struct InvalidIter : ValidIter { + int operator*() = delete; + }; + + REQUIRE( !IsIterator::value ); +} + +TEST_CASE("IsIterator fails when missing copy-ctor", "[helpers]") { + struct InvalidIter : ValidIter { + InvalidIter(const InvalidIter&) = delete; + }; + + REQUIRE( !IsIterator::value ); +} + +TEST_CASE("IsIterator fails when missing copy assignment", "[helpers]") { + struct InvalidIter : ValidIter { + InvalidIter& operator=(const InvalidIter&) = delete; + }; + + REQUIRE( !IsIterator::value ); +} -TEST_CASE("SolidInt can be moved only once", "[helpers]") { - SolidInt i{3}; - SECTION("Doesn't throw on first move") { - REQUIRE_NOTHROW( SolidInt{std::move(i)} ); - } - SECTION("Throws on second move") { - SolidInt i2{std::move(i)}; - REQUIRE_THROWS( SolidInt i3{std::move(i2)} ); - } +TEST_CASE("IsIterator passes a valid iterator", "[helpers]") { + REQUIRE( IsIterator::value ); } From 7bb5eeac946deb3bcf1dec8e5741583dba241af9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 21 Feb 2015 20:11:40 -0500 Subject: [PATCH 1000/1866] builds heplers tests --- catchtest/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index 80dc8d25..4bbf3f42 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -46,6 +46,7 @@ progs = Split( iteratoriterator mixed + helpers ''' ) From 1e51cbbbb1fc175dabae8a148cc78f3f7dbbab06 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 21 Feb 2015 21:06:17 -0500 Subject: [PATCH 1001/1866] makes powerset iter == more correct compares the combinations sub iterators as well as the set_size --- powerset.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/powerset.hpp b/powerset.hpp index 964b0651..dee9bdf2 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -71,7 +71,8 @@ namespace iter { } bool operator==(const Iterator& other) const { - return this->set_size == other.set_size; + return this->set_size == other.set_size + && this->comb_iter == other.comb_iter; } }; From bb7d5162850a15f3ce2ec2811907cef75988b89b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 21 Feb 2015 21:25:51 -0500 Subject: [PATCH 1002/1866] tests powerset iterator copy ctor --- catchtest/test_powerset.cpp | 56 +++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/catchtest/test_powerset.cpp b/catchtest/test_powerset.cpp index 1b4faeb7..0bf2de99 100644 --- a/catchtest/test_powerset.cpp +++ b/catchtest/test_powerset.cpp @@ -32,26 +32,52 @@ TEST_CASE("powerset: empty sequence gives only empty set", "[powerset]") { } TEST_CASE("powerset: iterators can be compared", "[powerset]") { - const std::vector ns = {1, 2}; + std::vector ns = {1, 2}; + auto p = powerset(ns); + { + auto it = std::begin(p); + REQUIRE( it == std::begin(p) ); + REQUIRE_FALSE( it != std::begin(p) ); + REQUIRE( it != std::end(p) ); + REQUIRE_FALSE( it == std::end(p) ); + ++it; + REQUIRE_FALSE( it == std::begin(p) ); + REQUIRE( it != std::begin(p) ); + REQUIRE_FALSE( it == std::end(p) ); + REQUIRE( it != std::end(p) ); + ++it; + ++it; + ++it; + REQUIRE( it == std::end(p) ); + } + + ns.push_back(3); + { + auto it = std::begin(p); + auto it2 = std::begin(p); + std::advance(it, 4); + std::advance(it2, 4); + REQUIRE( it == it2 ); + ++it2; + REQUIRE( it != it2 ); + } + +} + +TEST_CASE("powerset: iterator copy ctor is correct", "[powerset]") { + // { {}, {1}, {2}, {1, 2} } + std::vector ns = {1, 2}; auto p = powerset(ns); auto it = std::begin(p); - REQUIRE( it == std::begin(p) ); - REQUIRE_FALSE( it != std::begin(p) ); - REQUIRE( it != std::end(p) ); - REQUIRE_FALSE( it == std::end(p) ); - ++it; - REQUIRE_FALSE( it == std::begin(p) ); - REQUIRE( it != std::begin(p) ); - REQUIRE_FALSE( it == std::end(p) ); - REQUIRE( it != std::end(p) ); - ++it; - ++it; - ++it; - REQUIRE( it == std::end(p) ); - REQUIRE_FALSE( it != std::end(p) ); + auto it2(it); + REQUIRE( it == it2 ); + ++it2; + REQUIRE( it != it2 ); + REQUIRE( std::begin(*it) == std::end(*it) ); } + TEST_CASE("powerset: binds to lvalues, moves rvalues", "[powerset]") { itertest::BasicIterable bi{1, 2}; SECTION("binds to lvalues") { From eca1005614cdf87939674e72845cd2f769b61e6a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 21 Feb 2015 21:26:17 -0500 Subject: [PATCH 1003/1866] makes powerset iterator copyable Iterator now holds a shared_ptr, iterators made as copies of it will shared a combinator. Each can get a new combinator without affecting the old one. --- powerset.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerset.hpp b/powerset.hpp index dee9bdf2..5635cc4e 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -31,7 +31,7 @@ namespace iter { private: typename std::remove_reference::type *container_p; std::size_t set_size; - std::unique_ptr comb; + std::shared_ptr comb; iterator_type comb_iter; iterator_type comb_end; From f7a82869253fbaf4324a0e83457d604cfbfb4aec Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 08:53:03 -0500 Subject: [PATCH 1004/1866] tests accumulate iterator requirements --- catchtest/test_accumulate.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/catchtest/test_accumulate.cpp b/catchtest/test_accumulate.cpp index 7912d8d5..f8f2d3d7 100644 --- a/catchtest/test_accumulate.cpp +++ b/catchtest/test_accumulate.cpp @@ -63,3 +63,9 @@ TEST_CASE("accumulate: postfix ++", "[accumulate]") { REQUIRE( *it == 5 ); } + +TEST_CASE("accumulate: iterator meets requirements", "[accumulate]") { + Vec ns{}; + auto a = accumulate(ns); + REQUIRE( itertest::IsIterator::value ); +} From 5e2deb8fc87d03101c16c3d4a34648f09b31b50b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 08:53:30 -0500 Subject: [PATCH 1005/1866] tests chain iterator requirements --- catchtest/test_chain.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/catchtest/test_chain.cpp b/catchtest/test_chain.cpp index 23aa98f4..c2a00fb0 100644 --- a/catchtest/test_chain.cpp +++ b/catchtest/test_chain.cpp @@ -143,6 +143,12 @@ TEST_CASE("chain: postfix ++", "[chain]") { REQUIRE( *it == 'b'); } +TEST_CASE("chain: iterator meets requirements", "[chain]") { + Vec ns{}; + auto c = chain(ns, ns); + REQUIRE( itertest::IsIterator::value ); +} + TEST_CASE("chain.from_iterable: basic test", "[chain.from_iterable]") { std::vector sv{"abc", "xyz"}; @@ -194,8 +200,16 @@ TEST_CASE("chain.from_iterable: moves rvalues and binds ref to lvalues", } } -TEST_CASE("chain.from_iterable: empty", "[empty]") { +TEST_CASE("chain.from_iterable: empty", "[chain.from_iterable]") { const std::vector v{}; auto ch = chain.from_iterable(v); REQUIRE( std::begin(ch) == std::end(ch) ); } + + +TEST_CASE("chain.from_iterable: iterator meets requirements", + "[chain.from_iterable]") { + const std::vector v{}; + auto c = chain(v); + REQUIRE( itertest::IsIterator::value ); +} From 879ac8ac092cc91b5e9ab52729371a6fd8cb9355 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 08:53:43 -0500 Subject: [PATCH 1006/1866] tests combinations iterator requirements --- catchtest/test_combinations.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/catchtest/test_combinations.cpp b/catchtest/test_combinations.cpp index e5c015df..dfdb0d0b 100644 --- a/catchtest/test_combinations.cpp +++ b/catchtest/test_combinations.cpp @@ -68,3 +68,11 @@ TEST_CASE("combinations: doesn't move or copy elements of iterable", (void)i; } } + +TEST_CASE("combinations: iterator meets requirements", "[combinations]") { + std::string s{"abc"}; + auto c = combinations(s, 1); + REQUIRE( itertest::IsIterator::value ); + auto&& row = *std::begin(c); + REQUIRE( itertest::IsIterator::value ); +} From b4b95184270831d399b30b2c6f200d9923315fd0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 08:54:07 -0500 Subject: [PATCH 1007/1866] tests comb_w_repl iterator requirements --- catchtest/test_combinations_with_replacement.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/catchtest/test_combinations_with_replacement.cpp b/catchtest/test_combinations_with_replacement.cpp index bfa688f1..c58aec6d 100644 --- a/catchtest/test_combinations_with_replacement.cpp +++ b/catchtest/test_combinations_with_replacement.cpp @@ -76,3 +76,12 @@ TEST_CASE("combinations_with_replacement: " (void)i; } } + +TEST_CASE("combinations_with_replacement: iterator meets requirements", + "[combinations_with_replacement]") { + std::string s{"abc"}; + auto c = combinations_with_replacement(s, 1); + REQUIRE( itertest::IsIterator::value ); + auto&& row = *std::begin(c); + REQUIRE( itertest::IsIterator::value ); +} From 0ff84eb82bb6151d39f137ce6a99d1850c1766ab Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 08:58:43 -0500 Subject: [PATCH 1008/1866] tests compress iterator requirements --- catchtest/test_compress.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/catchtest/test_compress.cpp b/catchtest/test_compress.cpp index 137f69c9..29a7c068 100644 --- a/catchtest/test_compress.cpp +++ b/catchtest/test_compress.cpp @@ -120,3 +120,10 @@ TEST_CASE("compress: nothing on empty data", "[compress]") { auto c = compress(ivec, bvec); REQUIRE( std::begin(c) == std::end(c) ); } + +TEST_CASE("compress: iterator meets requirements", "[compress]") { + std::string s{}; + std::vector bv; + auto c = compress(s, bv); + REQUIRE( itertest::IsIterator::value ); +} From 67e157e4a6cbaaf38fa86546aefe4cef6f9e94c3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 09:01:16 -0500 Subject: [PATCH 1009/1866] tests count iterator requirements --- catchtest/test_count.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/catchtest/test_count.cpp b/catchtest/test_count.cpp index 05134724..12b1347b 100644 --- a/catchtest/test_count.cpp +++ b/catchtest/test_count.cpp @@ -52,3 +52,8 @@ TEST_CASE("count: with step > 1", "[count]") { const std::vector vc{10, 12, 14, 16}; REQUIRE( v == vc ); } + +TEST_CASE("count: iterator meets requirements", "[count]") { + auto c = count(); + REQUIRE( itertest::IsIterator::value ); +} From d27194d63b221f62152997d2f3e81f52b033d151 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 09:01:31 -0500 Subject: [PATCH 1010/1866] tests cycle iterator requirements --- catchtest/test_cycle.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/catchtest/test_cycle.cpp b/catchtest/test_cycle.cpp index 7f3d4203..572e73d6 100644 --- a/catchtest/test_cycle.cpp +++ b/catchtest/test_cycle.cpp @@ -50,3 +50,9 @@ TEST_CASE("cycle: doesn't move or copy elements of iterable", auto c = cycle(arr); *std::begin(c); } + +TEST_CASE("cycle: iterator meets requirements", "[cycle]") { + std::string s{}; + auto c = cycle(s); + REQUIRE( itertest::IsIterator::value ); +} From 9bd15bea3ccde36c3442adbc7333b2fbdcec738b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 09:01:45 -0500 Subject: [PATCH 1011/1866] tests dropwhile iterator requirements --- catchtest/test_dropwhile.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/catchtest/test_dropwhile.cpp b/catchtest/test_dropwhile.cpp index 07b6b907..7a4d7dee 100644 --- a/catchtest/test_dropwhile.cpp +++ b/catchtest/test_dropwhile.cpp @@ -83,3 +83,9 @@ TEST_CASE("dropwhile: doesn't move or copy elements of iterable", (void)i; } } + +TEST_CASE("dropwhile: iterator meets requirements", "[dropwhile]") { + std::string s{}; + auto c = dropwhile([]{return true;}, s); + REQUIRE( itertest::IsIterator::value ); +} From aaa41f6794b9cb9526ad3c4ca2c08040afc3afc5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 09:05:13 -0500 Subject: [PATCH 1012/1866] tests enumerate iterator requirements --- catchtest/test_enumerate.cpp | 7 +++++++ catchtest/test_filter.cpp | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/catchtest/test_enumerate.cpp b/catchtest/test_enumerate.cpp index 6fb747b8..1a899bc2 100644 --- a/catchtest/test_enumerate.cpp +++ b/catchtest/test_enumerate.cpp @@ -114,3 +114,10 @@ TEST_CASE("Doesn't move or copy elements of iterable", "[enumerate]") { (void)i; } } + + +TEST_CASE("enumerate: iterator meets requirements", "[enumerate]") { + std::string s{}; + auto c = enumerate(s); + REQUIRE( itertest::IsIterator::value ); +} diff --git a/catchtest/test_filter.cpp b/catchtest/test_filter.cpp index 985e38e2..28d597d3 100644 --- a/catchtest/test_filter.cpp +++ b/catchtest/test_filter.cpp @@ -109,3 +109,9 @@ TEST_CASE("filter: doesn't move or copy elements of iterable", "[filter]") { (void)i; } } + +TEST_CASE("filter: iterator meets requirements", "[filter]") { + std::string s{}; + auto c = filter([]{return true;}, s); + REQUIRE( itertest::IsIterator::value ); +} From 99742e329801cfb2a284541930b7e4adf501a613 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 09:05:54 -0500 Subject: [PATCH 1013/1866] tests filterfalse iterator requirements --- catchtest/test_filterfalse.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/catchtest/test_filterfalse.cpp b/catchtest/test_filterfalse.cpp index ca6ec915..cb09d897 100644 --- a/catchtest/test_filterfalse.cpp +++ b/catchtest/test_filterfalse.cpp @@ -92,3 +92,9 @@ TEST_CASE("filterfalse: all elements pass predicate", "[filterfalse]") { REQUIRE( std::begin(f) == std::end(f) ); } + +TEST_CASE("filterfalse: iterator meets requirements", "[filterfalse]") { + std::string s{}; + auto c = filterfalse([]{return true;}, s); + REQUIRE( itertest::IsIterator::value ); +} From 57e001460b9cccc2c5cf6d6e96be8da8ea6da671 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 09:06:09 -0500 Subject: [PATCH 1014/1866] tests groupby iterator requirements --- catchtest/test_groupby.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/catchtest/test_groupby.cpp b/catchtest/test_groupby.cpp index 943f99dc..06139d7b 100644 --- a/catchtest/test_groupby.cpp +++ b/catchtest/test_groupby.cpp @@ -161,3 +161,14 @@ TEST_CASE("groupby: doesn't double dereference", "[groupby]") { } } } + +TEST_CASE("groupby: iterator and groupiterator are correct", "[groupby]") { + std::string s{"abc"}; + auto c = groupby(s); + auto it = std::begin(c); + REQUIRE( itertest::IsIterator::value ); + auto&& gp = (*it).second; + auto it2 = std::begin(gp); + REQUIRE( itertest::IsIterator::value ); + +} From 3125d55722ea3649b8fc56986758961dcccac04d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 09:07:28 -0500 Subject: [PATCH 1015/1866] tests grouper iterator requirements --- catchtest/test_grouper.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/catchtest/test_grouper.cpp b/catchtest/test_grouper.cpp index 27032464..bc09bc30 100644 --- a/catchtest/test_grouper.cpp +++ b/catchtest/test_grouper.cpp @@ -58,3 +58,9 @@ TEST_CASE("grouper: empty iterable gives empty grouper", "[grouper]") { auto g = grouper(ns, 1); REQUIRE( std::begin(g) == std::end(g) ); } + +TEST_CASE("grouper: iterator meets requirements", "[grouper]") { + std::string s{}; + auto c = grouper(s, 1); + REQUIRE( itertest::IsIterator::value ); +} From fa1600f121194be2491eb3f570a061f6a86e2276 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 09:07:42 -0500 Subject: [PATCH 1016/1866] tests imap iterator requirements --- catchtest/test_imap.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/catchtest/test_imap.cpp b/catchtest/test_imap.cpp index ba9ae171..71a70440 100644 --- a/catchtest/test_imap.cpp +++ b/catchtest/test_imap.cpp @@ -121,3 +121,8 @@ TEST_CASE("imap: postfix ++", "[imap]") { REQUIRE( it == std::end(im) ); } +TEST_CASE("imap: iterator meets requirements", "[imap]") { + std::string s{}; + auto c = imap([](char){return 1;}, s); + REQUIRE( itertest::IsIterator::value ); +} From 6ba0981269993246fce35a29c932739eaf46532e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 09:07:54 -0500 Subject: [PATCH 1017/1866] tests permutations iterator requirements --- catchtest/test_permutations.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/catchtest/test_permutations.cpp b/catchtest/test_permutations.cpp index 23eec08f..2e012131 100644 --- a/catchtest/test_permutations.cpp +++ b/catchtest/test_permutations.cpp @@ -80,3 +80,11 @@ TEST_CASE("permutations doesn't move or copy elements of iterable", (void)st; } } + +TEST_CASE("permutations: iterator meets requirements", "[permutations]") { + std::string s{"abc"}; + auto c = permutations(s); + REQUIRE( itertest::IsIterator::value ); + auto&& row = *std::begin(c); + REQUIRE( itertest::IsIterator::value ); +} From c81c36e999da6a1aecab59ee9ab23fe05780c2b6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 09:08:09 -0500 Subject: [PATCH 1018/1866] tests powrset iterator requirements --- catchtest/test_powerset.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/catchtest/test_powerset.cpp b/catchtest/test_powerset.cpp index 0bf2de99..7da82744 100644 --- a/catchtest/test_powerset.cpp +++ b/catchtest/test_powerset.cpp @@ -98,3 +98,11 @@ TEST_CASE("powerset: doesn't move or copy elements of iterable", "[powerset]"){ } } } + +TEST_CASE("powerset: iterator meets requirements", "[powerset]") { + std::string s{"abc"}; + auto c = powerset(s); + REQUIRE( itertest::IsIterator::value ); + auto&& row = *std::begin(c); + REQUIRE( itertest::IsIterator::value ); +} From 09844b2ea988d7723d8f85e64d2b19ceaad9d746 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 09:08:20 -0500 Subject: [PATCH 1019/1866] tests product iterator requirements --- catchtest/test_product.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/catchtest/test_product.cpp b/catchtest/test_product.cpp index 3e160d0f..fb6ea0cc 100644 --- a/catchtest/test_product.cpp +++ b/catchtest/test_product.cpp @@ -113,3 +113,9 @@ TEST_CASE("product: doesn't move or copy elements of iterable", "[product]") { (void)std::get<0>(t); } } + +TEST_CASE("product: iterator meets requirements", "[product]") { + std::string s{"abc"}; + auto c = product(s, s); + REQUIRE( itertest::IsIterator::value ); +} From f9925494812752b13825a5b8262f9cd8124c27c6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 09:08:37 -0500 Subject: [PATCH 1020/1866] tests range iterator requirements --- catchtest/test_range.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/catchtest/test_range.cpp b/catchtest/test_range.cpp index fbf50298..d5dc6d29 100644 --- a/catchtest/test_range.cpp +++ b/catchtest/test_range.cpp @@ -4,6 +4,7 @@ #include #include +#include "helpers.hpp" #include "catch.hpp" using Vec = const std::vector; @@ -189,4 +190,8 @@ TEST_CASE("range: using doubles detects empty ranges", "[range]") { auto r2 = range(0.0, 1.0, -1.0); REQUIRE(std::begin(r2) == std::end(r2)); } - + +TEST_CASE("range: iterator meets requirements", "[range]") { + auto r = range(5); + REQUIRE( itertest::IsIterator::value ); +} From cf18b40e5a054c8f14b03ba6b0e9769b11131ec3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 09:14:44 -0500 Subject: [PATCH 1021/1866] tests repeat iterator requirements --- catchtest/test_repeat.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/catchtest/test_repeat.cpp b/catchtest/test_repeat.cpp index 0f159d29..59d0256d 100644 --- a/catchtest/test_repeat.cpp +++ b/catchtest/test_repeat.cpp @@ -49,3 +49,7 @@ TEST_CASE("repeat: doesn't duplicate item", "[repeat]") { (void)*it; } +TEST_CASE("repeat: iterator meets requirements", "[repeat]") { + auto r = repeat(1); + REQUIRE( itertest::IsIterator::value ); +} From 63bd48a58a7cd223be08a94484cf0aee00ff85b9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 09:15:02 -0500 Subject: [PATCH 1022/1866] tests slice iterator requirements --- catchtest/test_slice.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/catchtest/test_slice.cpp b/catchtest/test_slice.cpp index 3d95380e..ea6f5e13 100644 --- a/catchtest/test_slice.cpp +++ b/catchtest/test_slice.cpp @@ -101,3 +101,9 @@ TEST_CASE("slice: with iterable doesn't move or copy elems", "[slice]") { (void)i; } } + +TEST_CASE("slice: iterator meets requirements", "[slice]") { + std::string s{"abcdef"}; + auto c = slice(s, 1, 3); + REQUIRE( itertest::IsIterator::value ); +} From 37bcc243abd2fd710d60dcd202beca0692b8ba61 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 09:15:21 -0500 Subject: [PATCH 1023/1866] tests sliding window iterator requirements --- catchtest/test_sliding_window.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/catchtest/test_sliding_window.cpp b/catchtest/test_sliding_window.cpp index 3bcd0878..d413b431 100644 --- a/catchtest/test_sliding_window.cpp +++ b/catchtest/test_sliding_window.cpp @@ -99,3 +99,9 @@ TEST_CASE("sliding window: doesn't copy elements", "[sliding_window]") { (void)*std::begin(i); } } + +TEST_CASE("sliding_window: iterator meets requirements", "[sliding_window]") { + std::string s{"abcdef"}; + auto c = sliding_window(s, 2); + REQUIRE( itertest::IsIterator::value ); +} From be3278750048d9bce4220cf2f9ff71533636c34e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 09:15:52 -0500 Subject: [PATCH 1024/1866] tests takewhile iterator requirements --- catchtest/test_takewhile.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/catchtest/test_takewhile.cpp b/catchtest/test_takewhile.cpp index aae3f481..1d28b4d2 100644 --- a/catchtest/test_takewhile.cpp +++ b/catchtest/test_takewhile.cpp @@ -95,3 +95,9 @@ TEST_CASE("takewhile: with iterable doesn't move or copy elements", (void)i; } } + +TEST_CASE("takewhile: iterator meets requirements", "[takewhile]") { + std::string s{}; + auto c = takewhile([]{return true;}, s); + REQUIRE( itertest::IsIterator::value ); +} From 366a9581b247a9ef20897c88c8de07d3090e640b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 09:16:09 -0500 Subject: [PATCH 1025/1866] tests unique_everseen iterator requirements --- catchtest/test_unique_everseen.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/catchtest/test_unique_everseen.cpp b/catchtest/test_unique_everseen.cpp index 31e712a2..4cd94cd2 100644 --- a/catchtest/test_unique_everseen.cpp +++ b/catchtest/test_unique_everseen.cpp @@ -38,3 +38,9 @@ TEST_CASE("unique everseen: moves rvalues, binds to lvalues", unique_everseen(std::move(bi)); REQUIRE( bi.was_moved_from() ); } + +TEST_CASE("unique_everseen: iterator meets requirements", "[unique_everseen]") { + std::string s{}; + auto c = unique_everseen(s); + REQUIRE( itertest::IsIterator::value ); +} From 308b048d221f9ba8f152751799dcfe6570b2549f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 09:16:20 -0500 Subject: [PATCH 1026/1866] tests unique_justseen iterator requirements --- catchtest/test_unique_justseen.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/catchtest/test_unique_justseen.cpp b/catchtest/test_unique_justseen.cpp index fcb9067b..4285f364 100644 --- a/catchtest/test_unique_justseen.cpp +++ b/catchtest/test_unique_justseen.cpp @@ -44,3 +44,9 @@ TEST_CASE("unique justseen: moves and binds correctly", "[unique_justseen]") { unique_justseen(std::move(bi)); REQUIRE( bi.was_moved_from() ); } + +TEST_CASE("unique_justseen: iterator meets requirements", "[unique_justseen]") { + std::string s{}; + auto c = unique_justseen(s); + REQUIRE( itertest::IsIterator::value ); +} From 67f1b89f0c2e14842902b299da50fa052863d9b7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 09:16:34 -0500 Subject: [PATCH 1027/1866] tests zip iterator requirements --- catchtest/test_zip.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/catchtest/test_zip.cpp b/catchtest/test_zip.cpp index 106c9444..f099c8eb 100644 --- a/catchtest/test_zip.cpp +++ b/catchtest/test_zip.cpp @@ -99,3 +99,11 @@ TEST_CASE("zip: postfix ++", "[zip]") { it++; REQUIRE( it == std::end(z) ); } + +TEST_CASE("zip: iterator meets requirements", "[zip]") { + std::string s{}; + auto c = zip(s); + REQUIRE( itertest::IsIterator::value ); + auto c2 = zip(s, s); + REQUIRE( itertest::IsIterator::value ); +} From e5383ac9adad59c6dd08f48cdf9d0e4e70ce5ff5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 09:16:44 -0500 Subject: [PATCH 1028/1866] tests zip_longest iterator requirements --- catchtest/test_zip_longest.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/catchtest/test_zip_longest.cpp b/catchtest/test_zip_longest.cpp index 1e12a68a..6fe8cf5a 100644 --- a/catchtest/test_zip_longest.cpp +++ b/catchtest/test_zip_longest.cpp @@ -141,3 +141,11 @@ TEST_CASE("zip_longest: doesn't move or copy elements", "[zip_longest]") { (void)std::get<0>(t); } } + +TEST_CASE("zip_longest: iterator meets requirements", "[zip_longest]") { + std::string s{}; + auto c = zip_longest(s); + REQUIRE( itertest::IsIterator::value ); + auto c2 = zip_longest(s, s); + REQUIRE( itertest::IsIterator::value ); +} From a755f8b906372b9557d369481802635120ea5fe4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 10:35:16 -0500 Subject: [PATCH 1029/1866] 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 1030/1866] 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 1031/1866] 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 1032/1866] 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 1033/1866] 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 84d478c73bb445fe7f9dc289c377cbcafcab2f49 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 11:28:20 -0500 Subject: [PATCH 1034/1866] uses universal refs in readme examples --- README.md | 64 +++++++++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 7d44c246..dcaaf0e2 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ appears as: ```c++ vector vec{2, 4, 6, 8}; -for (auto e : enumerate(vec)) { +for (auto&& e : enumerate(vec)) { cout << e.index << ": " << e.element @@ -104,7 +104,7 @@ Called as `filter(predicate, iterable)`. The predicate can be any callable. Prints values greater than 4: `5 6 7 8` ```c++ vector vec{1, 5, 4, 0, 6, 7, 3, 0, 2, 8, 3, 2, 1}; -for (auto i : filter([] (int i) { return i > 4; }, vec)) { +for (auto&& i : filter([] (int i) { return i > 4; }, vec)) { cout << i <<'\n'; } @@ -114,7 +114,7 @@ If no predicate is passed, the elements themselves are tested for truth Prints only non-zero values. ```c++ -for(auto i : filter(vec)) { +for(auto&& i : filter(vec)) { cout << i << '\n'; } ``` @@ -126,7 +126,7 @@ Similar to filter, but only prints values that are false under the predicate. Prints values not greater than 4: `1 4 3 2 3 2 1 ` ```c++ vector vec{1, 5, 4, 0, 6, 7, 3, 0, 2, 8, 3, 2, 1}; -for (auto i : filterfalse([] (int i) { return i > 4; }, vec)) { +for (auto&& i : filterfalse([] (int i) { return i > 4; }, vec)) { cout << i <<'\n'; } @@ -136,7 +136,7 @@ If no predicate is passed, the elements themselves are tested for truth. Prints only zero values. ```c++ -for(auto i : filterfalse(vec)) { +for(auto&& i : filterfalse(vec)) { cout << i << '\n'; } ``` @@ -149,7 +149,7 @@ otherwise it will not be very efficient Example Usage: ```c++ 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)) { +for (auto&& i : unique_everseen(v)) { std::cout << i << " "; }std::cout << std::endl; ``` @@ -163,7 +163,7 @@ case it will be better and more efficient to use. Example Usage: ```c++ 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)) { +for (auto&& i : unique_justseen(v)) { std::cout << i << " "; }std::cout << std::endl; ``` @@ -176,7 +176,7 @@ the predicate is encountered. Prints `1 2 3 4`. (5 is false under the predicate) ```c++ vector ivec{1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1}; -for (auto i : takewhile([] (int i) {return i < 5;}, ivec)) { +for (auto&& i : takewhile([] (int i) {return i < 5;}, ivec)) { cout << i << '\n'; } ``` @@ -189,7 +189,7 @@ the predicate. Prints `5 6 7 1 2` ```c++ vector ivec{1, 2, 3, 4, 5, 6, 7, 1, 2}; -for (auto i : dropwhile([] (int i) {return i < 5;}, ivec)) { +for (auto&& i : dropwhile([] (int i) {return i < 5;}, ivec)) { cout << i << '\n'; } ``` @@ -203,7 +203,7 @@ Repeatedly produce all values of an iterable. The loop will be infinite, so a Prints `1 2 3` repeatedly until `some_condition` is true ```c++ vector vec{1, 2, 3}; -for (auto i : cycle(vec)) { +for (auto&& i : cycle(vec)) { cout << i << '\n'; if (some_condition) { break; @@ -222,7 +222,7 @@ vector vec = { "abcde", "efghi" }; -for (auto gb : groupby(vec, [] (const string &s) {return s.length(); })) { +for (auto&& gb : groupby(vec, [] (const string &s) {return s.length(); })) { cout << "key: " << gb.first << '\n'; cout << "content: "; for (auto s : gb.second) { @@ -242,7 +242,7 @@ Differs from `std::accumulate` (which in my humble opinion should be named can see all of the intermediate results. By default, it keeps a running sum. Prints: `1 3 6 10 15` ```c++ -for (auto i : accumulate(range(1, 6))) { +for (auto&& i : accumulate(range(1, 6))) { cout << i << '\n'; } ``` @@ -252,7 +252,7 @@ than adding them. Prints: `1 2 6 24 120` ```c++ -for (auto i : accumulate(range(1, 6), std::multiplies{})) { +for (auto&& i : accumulate(range(1, 6), std::multiplies{})) { cout << i << '\n'; } ``` @@ -275,7 +275,7 @@ vector f{1.2,1.4,12.3,4.5,9.9}; vector s{"i","like","apples","alot","dude"}; array d{{1.2,1.2,1.2,1.2,1.2}}; -for (auto e : zip(i,f,s,d)) { +for (auto&& e : zip(i,f,s,d)) { cout << std::get<0>(e) << ' ' << std::get<1>(e) << ' ' << std::get<2>(e) << ' ' @@ -302,7 +302,7 @@ sequence. Prints the squares of the numbers in vec: `1 4 9 16 25` ```c++ vector vec{1, 2, 3, 4, 5}; -for (auto i : imap([] (int x) {return x * x;}, vec)) { +for (auto&& i : imap([] (int x) {return x * x;}, vec)) { cout << i << '\n'; } ``` @@ -312,7 +312,7 @@ each vector together, printing `11 23 35 47 59 71` ```c++ vector vec1{1, 3, 5, 7, 9, 11}; vector vec2{10, 20, 30, 40, 50, 60}; -for (auto i : imap([] (int x, int y) { return x + y; }, vec1, vec2)) { +for (auto&& i : imap([] (int x, int y) { return x + y; }, vec1, vec2)) { cout << i << '\n'; } ``` @@ -332,7 +332,7 @@ Prints `2 6` ```c++ vector ivec{1, 2, 3, 4, 5, 6}; vector bvec{false, true, false, false, false, true}; -for (auto i : compress(ivec, bvec) { +for (auto&& i : compress(ivec, bvec) { cout << i << '\n'; } ``` @@ -348,7 +348,7 @@ vector empty{}; vector vec1{1,2,3,4,5,6}; array arr1{{7,8,9,10}}; -for (auto i : chain(empty,vec1,arr1)) { +for (auto&& i : chain(empty,vec1,arr1)) { cout << i << '\n'; } ``` @@ -367,7 +367,7 @@ vector> matrix = { {6, 8, 9, 10, 11, 12} }; -for (auto i : chain.from_iterable(matrix)) { +for (auto&& i : chain.from_iterable(matrix)) { cout << i << '\n'; } ``` @@ -378,7 +378,7 @@ reversed Iterates over elements of a sequence in reverse order. ```c++ -for (auto i : reversed(a)) { +for (auto&& i : reversed(a)) { cout << i << '\n'; } ``` @@ -392,7 +392,7 @@ the range returned is [start,stop) where you only take every step element This outputs `0 3 6 9 12` ```c++ vector a{0,1,2,3,4,5,6,7,8,9,10,11,12,13}; -for (auto i : slice(a,0,15,3)) { +for (auto&& i : slice(a,0,15,3)) { cout << i << '\n'; } ``` @@ -418,8 +418,8 @@ take a section of size 4, output is: Example Usage: ```c++ std::vector v = {1,2,3,4,5,6,7,8,9}; -for (auto sec : sliding_window(v,4)) { - for (auto i : sec) { +for (auto&& sec : sliding_window(v,4)) { + for (auto&& i : sec) { std::cout << i << " "; i.get() = 90; //has to be accessed with get if you want to store references @@ -438,11 +438,11 @@ section sliding by only 1 it goes the length of the full section. Example usage: ```c++ std::vector v {1,2,3,4,5,6,7,8,9}; -for (auto sec : grouper(v,4)) +for (auto&& sec : grouper(v,4)) //each section will have 4 elements //except the last one may be cut short { - for (auto i : sec) { + for (auto&& i : sec) { std::cout << i << " "; i.get() *= 2; } @@ -461,7 +461,7 @@ 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,v2,v3,v4)) { +for (auto&& t : product(v1,v2,v3,v4)) { std::cout << std::get<0>(t) << ", " << std::get<1>(t) << ", " << std::get<2>(t) << ", " @@ -478,9 +478,9 @@ combinations_with_replacement Example usage: ```c++ std::vector v = {1,2,3,4,5}; -for (auto i : combinations(v,3)) { +for (auto&& i : combinations(v,3)) { //std::cout << i << std::endl; - for (auto j : i ) std::cout << j << " "; + for (auto&& j : i ) std::cout << j << " "; std::cout< v = {1,2,3,4,5}; -for (auto vec : permutations(v)) { - for (auto i : vec) { +for (auto&& vec : permutations(v)) { + for (auto&& i : vec) { std::cout << i << " "; } std::cout << std::endl; @@ -510,8 +510,8 @@ Generates every possible subset of a set, never run it since it runs in ðš¯(2^n Example usage: ```c++ std::vector vec {1,2,3,4,5,6,7,8,9}; -for (auto v : powerset(vec)) { - for (auto i : v) std::cout << i << " "; +for (auto&& v : powerset(vec)) { + for (auto&& i : v) std::cout << i << " "; std::cout << std::endl; } ``` From 09c8c7f964f2b624c07b091dcc7dd7050ed462d7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 11:29:28 -0500 Subject: [PATCH 1035/1866] adds missing && in groupby example --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dcaaf0e2..7d6b8668 100644 --- a/README.md +++ b/README.md @@ -225,7 +225,7 @@ vector vec = { for (auto&& gb : groupby(vec, [] (const string &s) {return s.length(); })) { cout << "key: " << gb.first << '\n'; cout << "content: "; - for (auto s : gb.second) { + for (auto&& s : gb.second) { cout << s << " "; } cout << '\n'; From 429101fe7a39964cf7dc7e691be620229829facf Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 2 Apr 2015 17:06:14 -0400 Subject: [PATCH 1036/1866] eliminates shadowing in accumulate --- accumulate.hpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index 06f22168..e0dbb137 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -46,9 +46,10 @@ namespace iter { std::is_default_constructible::value, "Cannot accumulate a non-default constructible type"); - Accumulator(Container&& container, AccumulateFunc accumulate_func) - : container(std::forward(container)), - accumulate_func(accumulate_func) + Accumulator(Container&& in_container, + AccumulateFunc in_accumulate_func) + : container(std::forward(in_container)), + accumulate_func(in_accumulate_func) { } public: @@ -63,10 +64,10 @@ namespace iter { public: Iterator (iterator_type&& iter, iterator_type&& end, - AccumulateFunc accumulate_func) + AccumulateFunc in_accumulate_func) : sub_iter{std::move(iter)}, sub_end{std::move(end)}, - accumulate_func(accumulate_func), + accumulate_func(in_accumulate_func), // only get first value if not an end iterator acc_val(!(iter != end) ? AccumVal{} : *iter) { } From 367734f41af14b2c31f7fd320aa6a42132bd7bc0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 2 Apr 2015 17:10:07 -0400 Subject: [PATCH 1037/1866] eliminates shadow warnings from chain --- chain.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/chain.hpp b/chain.hpp index a05a39da..65e15a36 100644 --- a/chain.hpp +++ b/chain.hpp @@ -30,8 +30,8 @@ namespace iter { private: Container container; Chained rest_chained; - Chained(Container&& container, RestContainers&&... rest) - : container(std::forward(container)), + Chained(Container&& in_container, RestContainers&&... rest) + : container(std::forward(in_container)), rest_chained{std::forward(rest)...} { } @@ -52,10 +52,10 @@ namespace iter { public: Iterator(iterator_type&& s_begin, iterator_type&& s_end, - RestIter&& rest_iter) + RestIter&& in_rest_iter) : sub_iter{std::move(s_begin)}, sub_end{std::move(s_end)}, - rest_iter{std::move(rest_iter)}, + rest_iter{std::move(in_rest_iter)}, at_end{!(sub_iter != sub_end)} { } @@ -112,8 +112,8 @@ namespace iter { private: Container container; - Chained(Container&& container) - : container(std::forward(container)) + Chained(Container&& in_container) + : container(std::forward(in_container)) { } public: @@ -173,8 +173,8 @@ namespace iter { private: Container container; friend class ChainMaker; - ChainedFromIterable(Container&& container) - : container(std::forward(container)) + ChainedFromIterable(Container&& in_container) + : container(std::forward(in_container)) { } public: From 67a87efddc346aca8c47926faf785c992892df63 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 2 Apr 2015 17:11:12 -0400 Subject: [PATCH 1038/1866] eliminates shadow warnings from zip --- zip.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zip.hpp b/zip.hpp index 285146a8..ca3ed78b 100644 --- a/zip.hpp +++ b/zip.hpp @@ -31,8 +31,8 @@ namespace iter { private: Container container; Zipped rest_zipped; - Zipped(Container&& container, RestContainers&&... rest) - : container(std::forward(container)), + Zipped(Container&& in_container, RestContainers&&... rest) + : container(std::forward(in_container)), rest_zipped{std::forward(rest)...} { } From 7d8667497a45a4cbc359873b2953fdeb2adf3e21 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 2 Apr 2015 17:12:56 -0400 Subject: [PATCH 1039/1866] eliminates shadow warnings from comb_w_repl --- combinations_with_replacement.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index bfb8a9b1..900e563e 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -37,8 +37,8 @@ namespace iter { combinations_with_replacement( std::initializer_list, std::size_t); - CombinatorWithReplacement(Container&& container, std::size_t n) - : container(std::forward(container)), + CombinatorWithReplacement(Container&& in_container, std::size_t n) + : container(std::forward(in_container)), length{n} { } From c895551c4b39bacfa1bc2186535a2d04376b7fd7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 2 Apr 2015 17:14:53 -0400 Subject: [PATCH 1040/1866] eliminates shadow warnings from compress --- compress.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compress.hpp b/compress.hpp index 29318fe3..404f3047 100644 --- a/compress.hpp +++ b/compress.hpp @@ -57,9 +57,9 @@ namespace iter { using selector_iter_type = decltype(std::begin(selectors)); // Value constructor for use only in the compress function - Compressed(Container&& container, Selector&& selectors) - : container(std::forward(container)), - selectors(std::forward(selectors)) + Compressed(Container&& in_container, Selector&& in_selectors) + : container(std::forward(in_container)), + selectors(std::forward(in_selectors)) { } public: From 237c5cd6b6addee344db3293d198f68454b0bc82 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 2 Apr 2015 17:16:21 -0400 Subject: [PATCH 1041/1866] eliminates shadow warnings from cycle --- cycle.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cycle.hpp b/cycle.hpp index d63403ba..5745340b 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -28,8 +28,8 @@ namespace iter { Container container; - Cycle(Container&& container) - : container(std::forward(container)) + Cycle(Container&& in_container) + : container(std::forward(in_container)) { } public: @@ -44,10 +44,10 @@ namespace iter { iterator_type end; public: Iterator (const iterator_type& iter, - iterator_type&& end) + iterator_type&& in_end) : sub_iter{iter}, begin{iter}, - end{std::move(end)} + end{std::move(in_end)} { } iterator_deref operator*() { From 2558be9cb15c9d60004c766af2f67b9890431b7f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 2 Apr 2015 17:17:22 -0400 Subject: [PATCH 1042/1866] replaces <> with "" for include of iterbase --- dropwhile.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index a89e5a81..bb156ed4 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -1,7 +1,7 @@ #ifndef ITER_DROPWHILE_H_ #define ITER_DROPWHILE_H_ -#include +#include "iterbase.hpp" #include #include From 4a3e7e3ee9d50d99f3c77d7397ceec36c4d4e849 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 2 Apr 2015 17:18:20 -0400 Subject: [PATCH 1043/1866] eliminates shadow warnings from dropwhile --- dropwhile.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index bb156ed4..d5c9947f 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -32,9 +32,9 @@ namespace iter { friend DropWhile> dropwhile( FF, std::initializer_list); - DropWhile(FilterFunc filter_func, Container&& container) - : container(std::forward(container)), - filter_func(filter_func) + DropWhile(FilterFunc in_filter_func, Container&& in_container) + : container(std::forward(in_container)), + filter_func(in_filter_func) { } public: @@ -66,10 +66,10 @@ namespace iter { public: Iterator(iterator_type&& iter, iterator_type&& end, - FilterFunc& filter_func) + FilterFunc& in_filter_func) : sub_iter{std::move(iter)}, sub_end{std::move(end)}, - filter_func(&filter_func) + filter_func(&in_filter_func) { if (this->sub_iter != this->sub_end) { this->item.reset(*this->sub_iter); From 5c0eb12263be9bdf47c38e51084541150487b525 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 2 Apr 2015 17:19:34 -0400 Subject: [PATCH 1044/1866] eliminates shadow warnings from enumerate --- enumerate.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index c9b7ee76..2775232a 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -47,8 +47,8 @@ namespace iter { using BasePair = std::pair>; // Value constructor for use only in the enumerate function - Enumerable(Container&& container) - : container(std::forward(container)) + Enumerable(Container&& in_container) + : container(std::forward(in_container)) { } public: From 5ae6b83b33a9f2a8e4429e61e81fc17aa7cf6d9f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 2 Apr 2015 17:20:58 -0400 Subject: [PATCH 1045/1866] eliminates shadow warnings from filter --- filter.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/filter.hpp b/filter.hpp index b9136874..60a1be0d 100644 --- a/filter.hpp +++ b/filter.hpp @@ -35,9 +35,9 @@ namespace iter { FF, std::initializer_list); // Value constructor for use only in the filter function - Filter(FilterFunc filter_func, Container&& container) - : container(std::forward(container)), - filter_func(filter_func) + Filter(FilterFunc in_filter_func, Container&& in_container) + : container(std::forward(in_container)), + filter_func(in_filter_func) { } public: @@ -71,10 +71,10 @@ namespace iter { public: Iterator (iterator_type iter, iterator_type end, - FilterFunc& filter_func) + FilterFunc& in_filter_func) : sub_iter{iter}, sub_end{end}, - filter_func(&filter_func) + filter_func(&in_filter_func) { if (this->sub_iter != this->sub_end) { this->item.reset(*this->sub_iter); From 116e944b7d66cb009692e59f3abe665c3239fefd Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 2 Apr 2015 17:22:23 -0400 Subject: [PATCH 1046/1866] eliminates shadow warnings from filterfalse --- filterfalse.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/filterfalse.hpp b/filterfalse.hpp index 3bad5fa0..247fa84b 100644 --- a/filterfalse.hpp +++ b/filterfalse.hpp @@ -18,8 +18,8 @@ namespace iter { FilterFunc filter_func; public: - PredicateFlipper(FilterFunc filter_func) : - filter_func(filter_func) + PredicateFlipper(FilterFunc in_filter_func) : + filter_func(in_filter_func) { } PredicateFlipper() = delete; From f6d5a069215bd87dfce01de115f38a1634f23e0b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 2 Apr 2015 17:23:58 -0400 Subject: [PATCH 1047/1866] eliminates shadow warnings from groupby --- groupby.hpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index 0e754c15..488c93f3 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -35,9 +35,9 @@ namespace iter { using key_func_ret = typename std::result_of)>::type; - GroupBy(Container&& container, KeyFunc key_func) - : container(std::forward(container)), - key_func(key_func) + GroupBy(Container&& in_container, KeyFunc in_key_func) + : container(std::forward(in_container)), + key_func(in_key_func) { } public: @@ -68,10 +68,10 @@ namespace iter { public: Iterator(iterator_type&& si, iterator_type&& end, - KeyFunc& key_func) + KeyFunc& in_key_func) : sub_iter{std::move(si)}, sub_end{std::move(end)}, - key_func(&key_func) + key_func(&in_key_func) { if (this->sub_iter != this->sub_end) { this->item.reset(*this->sub_iter); @@ -146,9 +146,9 @@ namespace iter { // when called. bool completed = false; - Group(Iterator& owner, key_func_ret key) : - owner(owner), - key(key) + Group(Iterator& in_owner, key_func_ret in_key) : + owner(in_owner), + key(in_key) { } public: @@ -189,8 +189,8 @@ namespace iter { public: GroupIterator(Group *in_group_p, - key_func_ret& key) - : key{&key}, + key_func_ret& in_key) + : key{&in_key}, group_p{in_group_p} { } From c5594de9db795024aefbf4c949cf714ef210d1ea Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 2 Apr 2015 17:27:49 -0400 Subject: [PATCH 1048/1866] eliminates shadow warnings from imap --- imap.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/imap.hpp b/imap.hpp index 168cfd99..f4cf1279 100644 --- a/imap.hpp +++ b/imap.hpp @@ -91,9 +91,9 @@ namespace iter { map_func, *std::begin(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(MapFunc in_map_func, Containers&&... in_containers) : + map_func(in_map_func), + zipped(zip(std::forward(in_containers)...)) { } public: @@ -106,8 +106,8 @@ namespace iter { ZippedIterType zipiter; public: - Iterator(MapFunc& map_func, ZippedIterType&& in_zipiter) : - map_func(&map_func), + Iterator(MapFunc& in_map_func, ZippedIterType&& in_zipiter) : + map_func(&in_map_func), zipiter(std::move(in_zipiter)) { } From 3992376ca5ae1bbffa6272b4c3bc6a306430059a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 2 Apr 2015 17:29:37 -0400 Subject: [PATCH 1049/1866] eliminates shadow warnings from product --- product.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/product.hpp b/product.hpp index 44210a51..72ef1b36 100644 --- a/product.hpp +++ b/product.hpp @@ -33,8 +33,8 @@ namespace iter { private: Container container; Productor rest_products; - Productor(Container&& container, RestContainers&&... rest) - : container(std::forward(container)), + Productor(Container&& in_container, RestContainers&&... rest) + : container(std::forward(in_container)), rest_products{std::forward(rest)...} { } From 9d2f2b1ff0e750b3ad664b91fe6281d9e770788d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 2 Apr 2015 17:33:25 -0400 Subject: [PATCH 1050/1866] eliminates shadow warnings from range --- range.hpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/range.hpp b/range.hpp index f0e7048c..7a0017d3 100644 --- a/range.hpp +++ b/range.hpp @@ -49,16 +49,16 @@ namespace iter { const T stop; const T step; - Range(T stop) + Range(T in_stop) : start{0}, - stop{stop}, + stop{in_stop}, step{1} { } - Range(T start, T stop, T step =1) - : start{start}, - stop{stop}, - step{step} + Range(T in_start, T in_stop, T in_step =1) + : start{in_start}, + stop{in_stop}, + step{in_step} { } public: @@ -82,9 +82,9 @@ namespace iter { && !(this->step < 0 && this->value <= other.value); } public: - Iterator(T val, T step) + Iterator(T val, T in_step) : value{val}, - step{step} + step{in_step} { } T operator*() const { @@ -152,16 +152,16 @@ namespace iter { const T stop; const T step; - Range(T stop) + Range(T in_stop) : start{0}, - stop{stop}, + stop{in_stop}, step{1} { } - Range(T start, T stop, T step =1) - : start{start}, - stop{stop}, - step{step} + Range(T in_start, T in_stop, T in_step =1) + : start{in_start}, + stop{in_stop}, + step{in_step} { } public: class Iterator @@ -174,10 +174,10 @@ namespace iter { unsigned long steps_taken =0; public: - Iterator(T start, T step) - : start{start}, - value{start}, - step{step} + Iterator(T in_start, T in_step) + : start{in_start}, + value{in_start}, + step{in_step} { } bool operator!=(const Iterator& other) const { From ab5155450b43d2330bcbfb915621f1cc8af91dfe Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 2 Apr 2015 17:37:41 -0400 Subject: [PATCH 1051/1866] eliminates shadow warnings in reversed --- reversed.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/reversed.hpp b/reversed.hpp index b9427f72..0e03b6c1 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -20,8 +20,8 @@ namespace iter { Container container; friend Reverser reversed(Container&&); - Reverser(Container&& container) - : container(std::forward(container)) + Reverser(Container&& in_container) + : container(std::forward(in_container)) { } public: @@ -88,8 +88,8 @@ namespace iter { friend Reverser reversed(T (&)[N]); // Value constructor for use only in the reversed function - Reverser(T *array) - : array{array} + Reverser(T *in_array) + : array{in_array} { } public: From 63d86a41fb9a5ae0c3ffcb5500b11e05b78db695 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 2 Apr 2015 17:38:59 -0400 Subject: [PATCH 1052/1866] eliminates shadow warnings in slice --- slice.hpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/slice.hpp b/slice.hpp index f31e164b..2dfac39d 100644 --- a/slice.hpp +++ b/slice.hpp @@ -33,12 +33,12 @@ namespace iter { //template //friend Slice> slice(std::initializer_list); public: - Slice(Container&& in_container, DifferenceType start, - DifferenceType stop, DifferenceType step) + Slice(Container&& in_container, DifferenceType in_start, + DifferenceType in_stop, DifferenceType in_step) : container(std::forward(in_container)), - start{start < stop && step > 0 ? start : stop}, - stop{stop}, - step{step} + start{in_start < in_stop && in_step > 0 ? in_start : in_stop}, + stop{in_stop}, + step{in_step} { } @@ -56,14 +56,14 @@ namespace iter { public: Iterator (iterator_type&& si, iterator_type&& se, - DifferenceType start, - DifferenceType stop, - DifferenceType step) + DifferenceType in_start, + DifferenceType in_stop, + DifferenceType in_step) : sub_iter{std::move(si)}, sub_end{std::move(se)}, - current{start}, - stop{stop}, - step{step} + current{in_start}, + stop{in_stop}, + step{in_step} { } iterator_deref operator*() { From f7480e183f6afa2350898ad1153db284c9c80d1e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 2 Apr 2015 17:39:49 -0400 Subject: [PATCH 1053/1866] eliminates shadow warnings from sliding_window --- sliding_window.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sliding_window.hpp b/sliding_window.hpp index 7780f183..8d3526e0 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -31,8 +31,8 @@ namespace iter { friend SlidingWindow> sliding_window( std::initializer_list, std::size_t); - SlidingWindow(Container&& container, std::size_t win_sz) - : container(std::forward(container)), + SlidingWindow(Container&& in_container, std::size_t win_sz) + : container(std::forward(in_container)), window_size{win_sz} { } From a803bc30308d55b649e64b281969097f6b8290f8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 2 Apr 2015 17:41:23 -0400 Subject: [PATCH 1054/1866] eliminates shadow warnings in takewhile --- takewhile.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/takewhile.hpp b/takewhile.hpp index bd518c32..2c27c715 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -33,9 +33,9 @@ namespace iter { friend TakeWhile> takewhile( FF, std::initializer_list); - TakeWhile(FilterFunc filter_func, Container&& container) - : container(std::forward(container)), - filter_func(filter_func) + TakeWhile(FilterFunc in_filter_func, Container&& in_container) + : container(std::forward(in_container)), + filter_func(in_filter_func) { } @@ -68,10 +68,10 @@ namespace iter { public: Iterator(iterator_type&& iter, iterator_type&& end, - FilterFunc& filter_func) + FilterFunc& in_filter_func) : sub_iter{std::move(iter)}, sub_end{std::move(end)}, - filter_func(&filter_func) + filter_func(&in_filter_func) { if (this->sub_iter != this->sub_end) { this->item.reset(*this->sub_iter); From b4bc10959332f69db9643c2ac615f038d121481e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 2 Apr 2015 17:43:24 -0400 Subject: [PATCH 1055/1866] eliminates shadow warnings from zip_longest --- zip_longest.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zip_longest.hpp b/zip_longest.hpp index 044a9191..ecc973c4 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -38,8 +38,8 @@ namespace iter { Container container; ZippedLongest rest_zipped; - ZippedLongest(Container&& container, RestContainers&&... rest) - : container(std::forward(container)), + ZippedLongest(Container&& in_container, RestContainers&&... rest) + : container(std::forward(in_container)), rest_zipped{std::forward(rest)...} { } From 423b91c775c891f9cfbf8c17d358082d333a35ab Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 2 Apr 2015 18:05:24 -0400 Subject: [PATCH 1056/1866] marks zip_longest constexpr funcs as const --- zip_longest.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/zip_longest.hpp b/zip_longest.hpp index ecc973c4..d1cc3e0f 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -126,7 +126,7 @@ namespace iter { return *this; } - constexpr Iterator operator++(int) { + constexpr Iterator operator++(int) const { return *this; } @@ -138,16 +138,16 @@ namespace iter { return true; } - constexpr std::tuple<> operator*() { + constexpr std::tuple<> operator*() const { return {}; } }; - constexpr Iterator begin() { + constexpr Iterator begin() const { return {}; } - constexpr Iterator end() { + constexpr Iterator end() const { return {}; } }; From b4c2e30625f9f37faf8861323e8110fe196cd38f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 4 Apr 2015 10:11:36 -0700 Subject: [PATCH 1057/1866] adds basic test for sorted --- catchtest/test_sorted.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 catchtest/test_sorted.cpp diff --git a/catchtest/test_sorted.cpp b/catchtest/test_sorted.cpp new file mode 100644 index 00000000..761c3493 --- /dev/null +++ b/catchtest/test_sorted.cpp @@ -0,0 +1,23 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include "helpers.hpp" +#include "catch.hpp" + +using iter::sorted; + +using Vec = const std::vector; + +TEST_CASE("sorted: iterates through a vector in sorted order", "[sorted]" ){ + Vec ns = {4, 0, 5, 1, 6, 7, 9, 3, 2, 8}; + auto s = sorted(ns); + Vec v(std::begin(s), std::end(s)); + Vec vc = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + REQUIRE( v == vc ); +} From 270b20e169393fcfb18b95877de798aebbc710c5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 4 Apr 2015 10:11:52 -0700 Subject: [PATCH 1058/1866] builds sorted test --- catchtest/SConstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index 4bbf3f42..615fb6d5 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -37,7 +37,7 @@ progs = Split( reversed slice sliding_window - + sorted takewhile unique_everseen unique_justseen From c6a0374620b879701bbf2bdc9bcb7bb89c2d147e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 4 Apr 2015 10:12:08 -0700 Subject: [PATCH 1059/1866] tests that elements can be modified through sorted --- catchtest/test_sorted.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/catchtest/test_sorted.cpp b/catchtest/test_sorted.cpp index 761c3493..f49d62cf 100644 --- a/catchtest/test_sorted.cpp +++ b/catchtest/test_sorted.cpp @@ -21,3 +21,12 @@ TEST_CASE("sorted: iterates through a vector in sorted order", "[sorted]" ){ Vec vc = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; REQUIRE( v == vc ); } + +TEST_CASE("sorted: can modify elements through sorted", "[sorted]") { + std::vector ns(3, 9); + for (auto&& n : sorted(ns)) { + n = -1; + } + Vec vc(3, -1); + REQUIRE( ns == vc ); +} From 11006b48d42d0405ae56c00e1b401fbadb026f36 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 4 Apr 2015 10:14:54 -0700 Subject: [PATCH 1060/1866] tests sorted with unordered set --- catchtest/test_sorted.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/catchtest/test_sorted.cpp b/catchtest/test_sorted.cpp index f49d62cf..4e441cf6 100644 --- a/catchtest/test_sorted.cpp +++ b/catchtest/test_sorted.cpp @@ -30,3 +30,12 @@ TEST_CASE("sorted: can modify elements through sorted", "[sorted]") { Vec vc(3, -1); REQUIRE( ns == vc ); } + +TEST_CASE("sorted: can iterate over unordered container", "[sorted]") { + std::unordered_set ns = {1, 3, 2, 0, 4}; + auto s = sorted(ns); + + Vec v(std::begin(s), std::end(s)); + Vec vc = {0, 1, 2, 3, 4}; + REQUIRE( v == vc ); +} From a5a621e6b92c718dd3d3f7e9cc19c04c70daa06a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 4 Apr 2015 10:16:39 -0700 Subject: [PATCH 1061/1866] tests sorted is empty when given empty sequence --- catchtest/test_sorted.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/catchtest/test_sorted.cpp b/catchtest/test_sorted.cpp index 4e441cf6..1a459402 100644 --- a/catchtest/test_sorted.cpp +++ b/catchtest/test_sorted.cpp @@ -39,3 +39,9 @@ TEST_CASE("sorted: can iterate over unordered container", "[sorted]") { Vec vc = {0, 1, 2, 3, 4}; REQUIRE( v == vc ); } + +TEST_CASE("sorted: empty when iterable is empty", "[sorted]") { + Vec ns{}; + auto s = sorted(ns); + REQUIRE( std::begin(s) == std::end(s) ); +} From 8661b3d533da54b61016c33ed35ff516114757b9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 4 Apr 2015 10:27:37 -0700 Subject: [PATCH 1062/1866] tests sorted with different functor types --- catchtest/test_sorted.cpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/catchtest/test_sorted.cpp b/catchtest/test_sorted.cpp index 1a459402..a1638ecd 100644 --- a/catchtest/test_sorted.cpp +++ b/catchtest/test_sorted.cpp @@ -45,3 +45,37 @@ TEST_CASE("sorted: empty when iterable is empty", "[sorted]") { auto s = sorted(ns); REQUIRE( std::begin(s) == std::end(s) ); } + +namespace { + bool int_greater_than(int lhs, int rhs) { + return lhs > rhs; + } + + struct IntGreaterThan { + bool operator() (int lhs, int rhs) const { + return lhs > rhs; + } + }; +} + +TEST_CASE("sorted: works with different functor types", "[sorted]") { + Vec ns = {4, 1, 3, 2, 0}; + std::vector v; + SECTION("with function pointer") { + auto s = sorted(ns, int_greater_than); + v.insert(v.begin(), std::begin(s), std::end(s)); + } + + SECTION("with callable object") { + auto s = sorted(ns, IntGreaterThan{}); + v.insert(v.begin(), std::begin(s), std::end(s)); + } + + SECTION("with lambda") { + auto s = sorted(ns, [](int lhs, int rhs){return lhs > rhs;}); + v.insert(v.begin(), std::begin(s), std::end(s)); + } + + Vec vc = {4, 3, 2, 1, 0}; + REQUIRE( v == vc ); +} From 1280b949a63c3e57ec8b6c5a9b15be7aa74f58fc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 4 Apr 2015 11:17:27 -0700 Subject: [PATCH 1063/1866] tests sorted moves and binds correctly --- catchtest/test_sorted.cpp | 83 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/catchtest/test_sorted.cpp b/catchtest/test_sorted.cpp index a1638ecd..854ddb0d 100644 --- a/catchtest/test_sorted.cpp +++ b/catchtest/test_sorted.cpp @@ -79,3 +79,86 @@ TEST_CASE("sorted: works with different functor types", "[sorted]") { Vec vc = {4, 3, 2, 1, 0}; REQUIRE( v == vc ); } + +namespace { +template +class BasicIterableWithConstDeref { + private: + T *data; + std::size_t size; + bool was_moved_from_ = false; + public: + BasicIterableWithConstDeref(std::initializer_list il) + : data{new T[il.size()]}, + size{il.size()} + { + // would like to use enumerate, can't because it's for unit + // testing enumerate + std::size_t i = 0; + for (auto&& e : il) { + data[i] = e; + ++i; + } + } + + BasicIterableWithConstDeref& operator=(BasicIterableWithConstDeref&&) = delete; + BasicIterableWithConstDeref& operator=(const BasicIterableWithConstDeref&) = delete; + BasicIterableWithConstDeref(const BasicIterableWithConstDeref&) = delete; + + BasicIterableWithConstDeref(BasicIterableWithConstDeref&& other) + : data{other.data}, + size{other.size} + { + other.data = nullptr; + other.was_moved_from_ = true; + } + + bool was_moved_from() const { + return this->was_moved_from_; + } + + ~BasicIterableWithConstDeref() { + delete [] this->data; + } + + class Iterator { + private: + T *p; + public: + Iterator(T *b) : p{b} { } + bool operator!=(const Iterator& other) const { + return this->p != other.p; + } + + Iterator& operator++() { + ++this->p; + return *this; + } + + T& operator*() { + return *this->p; + } + + const T& operator*() const { + return *this->p; + } + }; + + Iterator begin() { + return {this->data}; + } + + Iterator end() { + return {this->data + this->size}; + } +}; +} + +TEST_CASE("sorted: moves rvalues and binds to lvalues", "[sorted]") { + BasicIterableWithConstDeref bi{1, 2}; + sorted(bi); + REQUIRE_FALSE( bi.was_moved_from() ); + + sorted(std::move(bi)); + REQUIRE( bi.was_moved_from() ); +} From 0ffb2605b16bfbe8d698a4c0d5b025efa1d187f0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 4 Apr 2015 11:17:45 -0700 Subject: [PATCH 1064/1866] adds const_iterator_deref Which deduces the type of an iterator dereferenced in a const context. --- iterbase.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/iterbase.hpp b/iterbase.hpp index 1f962d84..dc65fcfc 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -28,6 +28,14 @@ namespace iter { using iterator_deref = decltype(*std::declval&>()); + // const_iteator_deref is the type obtained through dereferencing + // a const iterator& (note: not a const_iterator). ie: the result + // of Container::iterator::operator*() const + template + using const_iterator_deref = + decltype(*std::declval&>()); + + template using iterator_traits_deref = typename std::remove_reference>::type; From 136757a72444e5e15757dc9b5f37cfb1691ddce5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 4 Apr 2015 11:18:16 -0700 Subject: [PATCH 1065/1866] Uses correct std::less in sorted Needs to be const --- sorted.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sorted.hpp b/sorted.hpp index 5dbbdc9b..93e4a3c7 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -68,10 +68,10 @@ namespace iter { template auto sorted(Container&& container) -> decltype(sorted(std::forward(container), - std::less>())) + std::less>())) { return sorted(std::forward(container), - std::less>()); + std::less>()); } } From 7315351d098c2a0bc880ea51e37cb8916c6b2482 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 4 Apr 2015 11:20:56 -0700 Subject: [PATCH 1066/1866] tests sorted with SolidInt --- catchtest/test_sorted.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/catchtest/test_sorted.cpp b/catchtest/test_sorted.cpp index 854ddb0d..918dec7d 100644 --- a/catchtest/test_sorted.cpp +++ b/catchtest/test_sorted.cpp @@ -162,3 +162,12 @@ TEST_CASE("sorted: moves rvalues and binds to lvalues", "[sorted]") { sorted(std::move(bi)); REQUIRE( bi.was_moved_from() ); } + +TEST_CASE("sorted: doesn't move or copy elements of iterable", "[sorted]") { + using itertest::SolidInt; + constexpr SolidInt arr[] = {{6}, {7}, {8}}; + for (auto&& i : sorted(arr, [](const SolidInt& lhs, const SolidInt& rhs){ + return lhs.getint() < rhs.getint();})) { + (void)i; + } +} From 0477efb3e17a67d13c01d48562f28e79b08ba2c9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 4 Apr 2015 11:40:50 -0700 Subject: [PATCH 1067/1866] removes Functor from Sorted's type Since the comparison function is only used in the constructor, there's no reason to make it be a part of Sorted. Instead the constructor can now deduce the type of the compare function. --- sorted.hpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/sorted.hpp b/sorted.hpp index 93e4a3c7..c68171e3 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -9,25 +9,26 @@ #include namespace iter { - template + template class Sorted; template - Sorted sorted(Container&&, CompareFunc); + Sorted sorted(Container&&, CompareFunc); - template + template class Sorted { private: using IterIterWrap = IterIterWrapper>>; using ItIt = iterator_type; - friend Sorted - sorted(Container&&, CompareFunc); + + template + friend Sorted sorted(C&&, F); Container container; IterIterWrap sorted_iters; - + template Sorted(Container&& in_container, CompareFunc compare_func) : container(std::forward(in_container)) { @@ -60,7 +61,7 @@ namespace iter { }; template - Sorted sorted( + Sorted sorted( Container&& container, CompareFunc compare_func) { return {std::forward(container), compare_func}; } From 3bb32e7dfec9679bc9c4a57a01d68e13e4b37d51 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 4 Apr 2015 12:58:40 -0700 Subject: [PATCH 1068/1866] adds sorted() to the docs --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index 7d6b8668..8f33b5f9 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ evaluation wherever possible. [groupby](#groupby)
[accumulate](#accumulate)
[compress](#compress)
+[sorted](#sorted)
[chain](#chain)
[chain.from\_iterable](#chainfrom_iterable)
[reversed](#reversed)
@@ -337,6 +338,20 @@ for (auto&& i : compress(ivec, bvec) { } ``` +sorted +------ +Allows iteration over a sequence in sorted order. `sorted()` does +**not** produce a new sequence, copy elements, or modify the original +sequence. It only provides a way to iterate over existing elements. +The below outputs `0 1 2 3 4`. + +```c++ +unordered_set nums{4, 0, 2, 1, 3}; +for (auto&& i : sorted(nums)) { + cout << i << '\n'; +} +``` + chain ----- From a9c72cbdeb24c2cea3ca67712f1f27be7945dffb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 4 Apr 2015 13:03:57 -0700 Subject: [PATCH 1069/1866] mentions second sorted arg and requirements --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8f33b5f9..86a3b666 100644 --- a/README.md +++ b/README.md @@ -340,9 +340,15 @@ for (auto&& i : compress(ivec, bvec) { sorted ------ -Allows iteration over a sequence in sorted order. `sorted()` does +Allows iteration over a sequence in sorted order. `sorted` does **not** produce a new sequence, copy elements, or modify the original sequence. It only provides a way to iterate over existing elements. +`sorted` also takes an optional second +[comparator](http://en.cppreference.com/w/cpp/concept/Compare) +argument. If not provided, defaults to `std::less`.
+Iterables passed to sorted are required to have an iterator with +an `operator*() const` member. + The below outputs `0 1 2 3 4`. ```c++ From 56e33f051d3bf528bfac5cdf2519238dd2cdeb01 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 4 Apr 2015 13:11:21 -0700 Subject: [PATCH 1070/1866] adds repeat to the docs --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.md b/README.md index 86a3b666..98462cbe 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ evaluation wherever possible. [takewhile](#takewhile)
[dropwhile](#dropwhile)
[cycle](#cycle)
+[repeat](#repeat)
[groupby](#groupby)
[accumulate](#accumulate)
[compress](#compress)
@@ -212,6 +213,25 @@ for (auto&& i : cycle(vec)) { } ``` +repeat +------ +Repeatedly produces a single argument forever, or a given number of times. +`repeat` will bind a reference when passed an lvalue and move when given +an rvalue. It will then yield a reference to the same item until completion. + +The below prints `1` five times. +```c++ +for (auto&& e : repeat(1, 5)) { + cout << e << '\n'; +} +``` +The below prints `2` forever +```c++ +for (auto&& e : repeat(2)) { + cout << e << '\n'; +} +``` + groupby ------- Separate an iterable into groups sharing a common key. The following example From ed7ce408caab8a8c0cac6afe57da3fdfdae9dd80 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 4 Apr 2015 13:23:48 -0700 Subject: [PATCH 1071/1866] adds count to docs --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/README.md b/README.md index 98462cbe..81eda729 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ evaluation wherever possible. [dropwhile](#dropwhile)
[cycle](#cycle)
[repeat](#repeat)
+[count](#count)
[groupby](#groupby)
[accumulate](#accumulate)
[compress](#compress)
@@ -232,6 +233,28 @@ for (auto&& e : repeat(2)) { } ``` +count +----- +Effectively a `range` without a stopping point.
+`count()` with no arguments will start counting from 0 with a positive +step of 1.
+`count(i)` will start counting from `i` with a positive step of 1.
+`count(i, st)` will start counting from `i` with a step of `st`. + +*Technical limitations*: Unlike Python which can use its long integer +types when needed, count() will eventually exceed the +maximum possible value for its type (or minimum with a negative step). +When using a signed type it is up to the API user to ensure this does +not happen. If the limit is exceeded for signed types, the result is +undefined (as per the C++ standard). + +The below will print `0 1 2` ... etc +```c++ +for (auto&& i : count()) { + cout << i << '\n'; +} +``` + groupby ------- Separate an iterable into groups sharing a common key. The following example From a5aed68a560213e1237f6778d46e5ec1bcfbd99f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 4 Apr 2015 13:33:39 -0700 Subject: [PATCH 1072/1866] adds comb_w_repl to the docs --- README.md | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 81eda729..7fcfaf40 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ evaluation wherever possible. ##### Combinatoric fuctions [product](#product)
[combinations](#combinations)
+[combinations_with_replacement](#combinations_with_replacement) [permutations](#permutations)
[powerset](#powerset)
@@ -536,16 +537,33 @@ for (auto&& t : product(v1,v2,v3,v4)) { combinations ----------- -Generates n length unique sequences of the input range, there is also a -combinations_with_replacement +Generates n length unique sequences of the input range. Example usage: ```c++ -std::vector v = {1,2,3,4,5}; +vector v = {1,2,3,4,5}; for (auto&& i : combinations(v,3)) { - //std::cout << i << std::endl; - for (auto&& j : i ) std::cout << j << " "; - std::cout< Date: Sat, 4 Apr 2015 13:48:31 -0700 Subject: [PATCH 1073/1866] adds zip_longest to the docs --- README.md | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7fcfaf40..22627e5a 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ evaluation wherever possible. [range](#range)
[enumerate](#enumerate)
[zip](#zip)
+[zip_longest](#zip)
[imap](#imap)
[filter](#filter)
[filterfalse](#filterfalse)
@@ -329,12 +330,43 @@ for (auto&& e : zip(i,f,s,d)) { } ``` +zip_longest +----------- +Terminates on the longest sequence instead of the shortest. +Repeatedly yields a tuple of `boost::optional`s where `T` is the type +yielded by the sequences' respective iterators. Because of its boost +dependency, `zip_longest` is not in `itertools.hpp` and must be included +separately. +The following loop prints either "Just " or "Nothing" for each +element in each tuple yielded. + +```c++ +vector v1 = {0, 1, 2, 3}; +vector v2 = {10, 11}; +for (auto&& t : zip_longest(v1, v2)) { + cout << '{'; + if (std::get<0>(t)) { + cout << "Just " << *std::get<0>(t); + } else { + cout << "Nothing"; + } + cout << ", "; + if (std::get<1>(t)) { + cout << "Just " << *std::get<1>(t); + } else { + cout << "Nothing"; + } + cout << "}\n"; +} +``` -a `zip_longest` also exists where the range terminates on the longest -range instead of the shortest. because of that you have to return a -`boost::optional` where `T` is whatever type the iterator dereferenced -to (`std::optional` when it is released, if ever) - +The output is: +``` +{Just 0, Just 10} +{Just 1, Just 11} +{Just 2, Nothing} +{Just 3, Nothing} +``` imap ---- From 0bb0482b27bf76089ad35ee06a9463f2cfe1af27 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 4 Apr 2015 13:52:24 -0700 Subject: [PATCH 1074/1866] inserts missing br --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 22627e5a..e952655b 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ evaluation wherever possible. ##### Combinatoric fuctions [product](#product)
[combinations](#combinations)
-[combinations_with_replacement](#combinations_with_replacement) +[combinations_with_replacement](#combinations_with_replacement)
[permutations](#permutations)
[powerset](#powerset)
From 4a7dc7102713b862f121d74744dd9ff21d3dad06 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 4 Apr 2015 14:03:05 -0700 Subject: [PATCH 1075/1866] removes include of zip_longest from itertools.hpp Must be included explicitly --- itertools.hpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/itertools.hpp b/itertools.hpp index 8e84eed3..1f54acff 100644 --- a/itertools.hpp +++ b/itertools.hpp @@ -1,5 +1,5 @@ -#ifndef ITERTOOLS_HPP -#define ITERTOOLS_HPP +#ifndef ITERTOOLS_ALL_HPP_ +#define ITERTOOLS_ALL_HPP_ #include "accumulate.hpp" #include "chain.hpp" @@ -28,7 +28,9 @@ #include "unique_everseen.hpp" #include "unique_justseen.hpp" #include "zip.hpp" -#include "zip_longest.hpp" + +// zip_longest is the only itertool with a boost depedency, so it must be +// included explicitly #endif From dfee40438f886f7a8f067873b5c0a54eed88bf06 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 4 Apr 2015 18:25:12 -0700 Subject: [PATCH 1076/1866] 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 1036054836800260db1d436b67e3f896dc1ab6d1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 4 Apr 2015 18:55:42 -0700 Subject: [PATCH 1077/1866] tests that reversed iterator meets requirements --- catchtest/test_reversed.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/catchtest/test_reversed.cpp b/catchtest/test_reversed.cpp index 2fc2adc6..389badd0 100644 --- a/catchtest/test_reversed.cpp +++ b/catchtest/test_reversed.cpp @@ -60,3 +60,9 @@ TEST_CASE("reversed: with iterable doesn't move or copy elems", "[reversed]") { (void)i; } } + +TEST_CASE("reversed: iterator meets requirements", "[reversed]") { + Vec v; + auto r = reversed(v); + REQUIRE( itertest::IsIterator::value ); +} From ef1ae7513b98dd57e090667d1e8ed9eab9b6ac3b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 4 Apr 2015 19:00:02 -0700 Subject: [PATCH 1078/1866] 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 dd46ff387bcb392e3df481dacea2488187ebd1fc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 6 Apr 2015 21:54:01 -0700 Subject: [PATCH 1079/1866] includes requirements in readme --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e952655b..9c3c12de 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,15 @@ evaluation wherever possible. *Note*: Everthing is inside the `iter` namespace. -##### Table of Contents +#### Requirements +This library is **header-only** and relies only on the C++ standard +library. The only exception is `zip_longest` which uses `boost::optional`. +`#include ` will include all of the provided +tools except for `zip_longest` which must be included separately. You may +also include individual pieces with the relevant header +(`#include ` for example). + +#### Table of Contents [range](#range)
[enumerate](#enumerate)
[zip](#zip)
From a740829d2ff15c0869565bb526f81042c649c5f0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 7 Apr 2015 22:47:39 -0700 Subject: [PATCH 1080/1866] moves void_t into iterbase --- catchtest/helpers.hpp | 12 +- examples/.gitignore | 5 + examples/SConstruct | 51 ++++++++ examples/samples.hpp | 98 +++++++++++++++ examples/testaccumulate.cpp | 35 ++++++ examples/testchain.cpp | 61 +++++++++ examples/testchainfromiterable.cpp | 28 +++++ examples/testcombinations.cpp | 75 +++++++++++ .../testcombinations_with_replacement.cpp | 55 ++++++++ examples/testcommand_chains.cpp | 78 ++++++++++++ examples/testcompress.cpp | 67 ++++++++++ examples/testcount.cpp | 38 ++++++ examples/testcycle.cpp | 70 +++++++++++ examples/testdropwhile.cpp | 35 ++++++ examples/testenumerate.cpp | 60 +++++++++ examples/testfilter.cpp | 83 ++++++++++++ examples/testfilterfalse.cpp | 93 ++++++++++++++ examples/testgroupby.cpp | 109 ++++++++++++++++ examples/testgrouper.cpp | 51 ++++++++ examples/testimap.cpp | 45 +++++++ examples/testpermutations.cpp | 60 +++++++++ examples/testpowerset.cpp | 44 +++++++ examples/testproduct.cpp | 77 ++++++++++++ examples/testrange.cpp | 83 ++++++++++++ examples/testrepeat.cpp | 31 +++++ examples/testreversed.cpp | 43 +++++++ examples/testslice.cpp | 81 ++++++++++++ examples/testsliding_window.cpp | 53 ++++++++ examples/testsorted.cpp | 36 ++++++ examples/testtakewhile.cpp | 32 +++++ examples/testunique_everseen.cpp | 41 ++++++ examples/testunique_justseen.cpp | 35 ++++++ examples/testzip.cpp | 118 ++++++++++++++++++ examples/testzip_longest.cpp | 96 ++++++++++++++ iterbase.hpp | 12 ++ 35 files changed, 1982 insertions(+), 9 deletions(-) create mode 100644 examples/.gitignore create mode 100644 examples/SConstruct create mode 100644 examples/samples.hpp create mode 100644 examples/testaccumulate.cpp create mode 100644 examples/testchain.cpp create mode 100644 examples/testchainfromiterable.cpp create mode 100644 examples/testcombinations.cpp create mode 100644 examples/testcombinations_with_replacement.cpp create mode 100644 examples/testcommand_chains.cpp create mode 100644 examples/testcompress.cpp create mode 100644 examples/testcount.cpp create mode 100644 examples/testcycle.cpp create mode 100644 examples/testdropwhile.cpp create mode 100644 examples/testenumerate.cpp create mode 100644 examples/testfilter.cpp create mode 100644 examples/testfilterfalse.cpp create mode 100644 examples/testgroupby.cpp create mode 100644 examples/testgrouper.cpp create mode 100644 examples/testimap.cpp create mode 100644 examples/testpermutations.cpp create mode 100644 examples/testpowerset.cpp create mode 100644 examples/testproduct.cpp create mode 100644 examples/testrange.cpp create mode 100644 examples/testrepeat.cpp create mode 100644 examples/testreversed.cpp create mode 100644 examples/testslice.cpp create mode 100644 examples/testsliding_window.cpp create mode 100644 examples/testsorted.cpp create mode 100644 examples/testtakewhile.cpp create mode 100644 examples/testunique_everseen.cpp create mode 100644 examples/testunique_justseen.cpp create mode 100644 examples/testzip.cpp create mode 100644 examples/testzip_longest.cpp diff --git a/catchtest/helpers.hpp b/catchtest/helpers.hpp index 29203304..7c36ca89 100644 --- a/catchtest/helpers.hpp +++ b/catchtest/helpers.hpp @@ -1,6 +1,8 @@ #ifndef TEST_HELPER_H_ #define TEST_HELPER_H_ +#include + #include #include #include @@ -170,15 +172,7 @@ class BasicIterable { } }; - -// gcc CWG 1558 -template -struct void_t_help { - using type = void; -}; -template - -using void_t = typename void_t_help::type; +using iter::void_t; template struct IsIterator : std::false_type { }; diff --git a/examples/.gitignore b/examples/.gitignore new file mode 100644 index 00000000..a77d502e --- /dev/null +++ b/examples/.gitignore @@ -0,0 +1,5 @@ +*.o +*.swp +test* +!test*.cpp +.sconsign.dblite diff --git a/examples/SConstruct b/examples/SConstruct new file mode 100644 index 00000000..74195c1e --- /dev/null +++ b/examples/SConstruct @@ -0,0 +1,51 @@ +import os + +env = Environment( + ENV = {'PATH' : os.environ['PATH']}, + CXX='c++', + CXXFLAGS= ['-g', '-Wall', '-Wextra', + '-pedantic', '-std=c++11', + '-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 + 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/examples/samples.hpp b/examples/samples.hpp new file mode 100644 index 00000000..9faba373 --- /dev/null +++ b/examples/samples.hpp @@ -0,0 +1,98 @@ +#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*() /*const*/ { + 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/examples/testaccumulate.cpp b/examples/testaccumulate.cpp new file mode 100644 index 00000000..edf3d0a4 --- /dev/null +++ b/examples/testaccumulate.cpp @@ -0,0 +1,35 @@ +#include +#include + +#include +#include + +int main() { + // accumulate with a lambda for subtraction + 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'; + } + + // using a range instead of a vector + for (auto v : iter::accumulate(iter::range(10), + [](int a, int b){return a - b;})) { + std::cout << v << '\n'; + } + + // using a range and the default summing behavior + 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/examples/testchain.cpp b/examples/testchain.cpp new file mode 100644 index 00000000..19ab374d --- /dev/null +++ b/examples/testchain.cpp @@ -0,0 +1,61 @@ +#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; + } + } + { + 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/examples/testchainfromiterable.cpp b/examples/testchainfromiterable.cpp new file mode 100644 index 00000000..f4b6d599 --- /dev/null +++ b/examples/testchainfromiterable.cpp @@ -0,0 +1,28 @@ +#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/examples/testcombinations.cpp b/examples/testcombinations.cpp new file mode 100644 index 00000000..ee444b90 --- /dev/null +++ b/examples/testcombinations.cpp @@ -0,0 +1,75 @@ +#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/examples/testcompress.cpp b/examples/testcompress.cpp new file mode 100644 index 00000000..5197f3e2 --- /dev/null +++ b/examples/testcompress.cpp @@ -0,0 +1,67 @@ +#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/examples/testcount.cpp b/examples/testcount.cpp new file mode 100644 index 00000000..946d6841 --- /dev/null +++ b/examples/testcount.cpp @@ -0,0 +1,38 @@ +#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/examples/testcycle.cpp b/examples/testcycle.cpp new file mode 100644 index 00000000..138692cc --- /dev/null +++ b/examples/testcycle.cpp @@ -0,0 +1,70 @@ +#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/examples/testdropwhile.cpp b/examples/testdropwhile.cpp new file mode 100644 index 00000000..3140f81a --- /dev/null +++ b/examples/testdropwhile.cpp @@ -0,0 +1,35 @@ +#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/examples/testenumerate.cpp b/examples/testenumerate.cpp new file mode 100644 index 00000000..fcc1745c --- /dev/null +++ b/examples/testenumerate.cpp @@ -0,0 +1,60 @@ +#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/examples/testfilter.cpp b/examples/testfilter.cpp new file mode 100644 index 00000000..e8af2aab --- /dev/null +++ b/examples/testfilter.cpp @@ -0,0 +1,83 @@ +#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/examples/testfilterfalse.cpp b/examples/testfilterfalse.cpp new file mode 100644 index 00000000..9063d0bf --- /dev/null +++ b/examples/testfilterfalse.cpp @@ -0,0 +1,93 @@ +#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/examples/testgroupby.cpp b/examples/testgroupby.cpp new file mode 100644 index 00000000..9fc03ee3 --- /dev/null +++ b/examples/testgroupby.cpp @@ -0,0 +1,109 @@ +#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/examples/testgrouper.cpp b/examples/testgrouper.cpp new file mode 100644 index 00000000..b16ebc98 --- /dev/null +++ b/examples/testgrouper.cpp @@ -0,0 +1,51 @@ +#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/examples/testimap.cpp b/examples/testimap.cpp new file mode 100644 index 00000000..3d6f38ca --- /dev/null +++ b/examples/testimap.cpp @@ -0,0 +1,45 @@ +#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/examples/testpermutations.cpp b/examples/testpermutations.cpp new file mode 100644 index 00000000..a73a2a3b --- /dev/null +++ b/examples/testpermutations.cpp @@ -0,0 +1,60 @@ +#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/examples/testpowerset.cpp b/examples/testpowerset.cpp new file mode 100644 index 00000000..20ca0098 --- /dev/null +++ b/examples/testpowerset.cpp @@ -0,0 +1,44 @@ +#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/examples/testproduct.cpp b/examples/testproduct.cpp new file mode 100644 index 00000000..22d132ec --- /dev/null +++ b/examples/testproduct.cpp @@ -0,0 +1,77 @@ +#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/examples/testrange.cpp b/examples/testrange.cpp new file mode 100644 index 00000000..9404ae57 --- /dev/null +++ b/examples/testrange.cpp @@ -0,0 +1,83 @@ +#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/examples/testrepeat.cpp b/examples/testrepeat.cpp new file mode 100644 index 00000000..b91fba03 --- /dev/null +++ b/examples/testrepeat.cpp @@ -0,0 +1,31 @@ +#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/examples/testreversed.cpp b/examples/testreversed.cpp new file mode 100644 index 00000000..c6d0ab46 --- /dev/null +++ b/examples/testreversed.cpp @@ -0,0 +1,43 @@ +#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/examples/testslice.cpp b/examples/testslice.cpp new file mode 100644 index 00000000..eaf8e1ce --- /dev/null +++ b/examples/testslice.cpp @@ -0,0 +1,81 @@ +#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/examples/testsliding_window.cpp b/examples/testsliding_window.cpp new file mode 100644 index 00000000..16708db7 --- /dev/null +++ b/examples/testsliding_window.cpp @@ -0,0 +1,53 @@ +#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/examples/testsorted.cpp b/examples/testsorted.cpp new file mode 100644 index 00000000..aed57d32 --- /dev/null +++ b/examples/testsorted.cpp @@ -0,0 +1,36 @@ +#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/examples/testtakewhile.cpp b/examples/testtakewhile.cpp new file mode 100644 index 00000000..bec3aeae --- /dev/null +++ b/examples/testtakewhile.cpp @@ -0,0 +1,32 @@ +#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/examples/testunique_everseen.cpp b/examples/testunique_everseen.cpp new file mode 100644 index 00000000..015adb7d --- /dev/null +++ b/examples/testunique_everseen.cpp @@ -0,0 +1,41 @@ + +#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/examples/testunique_justseen.cpp b/examples/testunique_justseen.cpp new file mode 100644 index 00000000..8f454b6d --- /dev/null +++ b/examples/testunique_justseen.cpp @@ -0,0 +1,35 @@ + +#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/examples/testzip.cpp b/examples/testzip.cpp new file mode 100644 index 00000000..76a95fd7 --- /dev/null +++ b/examples/testzip.cpp @@ -0,0 +1,118 @@ +#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/examples/testzip_longest.cpp b/examples/testzip_longest.cpp new file mode 100644 index 00000000..63dc8fd0 --- /dev/null +++ b/examples/testzip_longest.cpp @@ -0,0 +1,96 @@ +#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< + struct type_is { + using type = T; + }; + + // gcc CWG 1558 + template + struct void_t_help { + using type = void; + }; + template + using void_t = typename void_t_help::type; } From afb2b623cced68f805433fea856b1127a03fedb5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 7 Apr 2015 22:49:13 -0700 Subject: [PATCH 1081/1866] lets iteratoriterator work with const things --- iteratoriterator.hpp | 72 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/iteratoriterator.hpp b/iteratoriterator.hpp index 5bd807bc..bf4fc35b 100644 --- a/iteratoriterator.hpp +++ b/iteratoriterator.hpp @@ -15,6 +15,13 @@ // behave like some_collection when iterated over or indexed namespace iter { + template + struct HasConstDeref : std::false_type { }; + + template + struct HasConstDeref())>> + : std::true_type { }; + template ::difference_type> class IteratorIterator : public std::iterator< @@ -142,8 +149,35 @@ namespace iter { using size_type = typename Container::size_type; using iterator = IteratorIterator; + using const_iterator = + IteratorIterator; using reverse_iterator = IteratorIterator; + using const_reverse_iterator = + IteratorIterator; + + template + struct ConstAtTypeOrVoid : type_is { }; + + template + struct ConstAtTypeOrVoid < + U, void_t().at(0))>> + : type_is().at(0))> + { }; + + using const_at_type_or_void_t = typename ConstAtTypeOrVoid<>::type; + + template + struct ConstIndexTypeOrVoid : type_is { }; + + template + struct ConstIndexTypeOrVoid < + U, void_t()[0])>> + : type_is()[0])> + { }; + + using const_index_type_or_void_t = + typename ConstIndexTypeOrVoid<>::type; public: IterIterWrapper() = default; @@ -160,7 +194,9 @@ namespace iter { return *container.at(pos); } - auto at(size_type pos) const -> decltype(*container.at(pos)) { + auto at(size_type pos) const -> + const_at_type_or_void_t + { return *container.at(pos); } @@ -173,7 +209,7 @@ namespace iter { auto operator[](size_type pos) const noexcept(noexcept(*container[pos])) - -> decltype(*container[pos]) + -> const_index_type_or_void_t { return *container[pos]; } @@ -194,6 +230,22 @@ namespace iter { return {container.end()}; } + const_iterator begin() const noexcept { + return {container.begin()}; + } + + const_iterator end() const noexcept { + return {container.end()}; + } + + const_iterator cbegin() const noexcept { + return {container.cbegin()}; + } + + const_iterator cend() const noexcept { + return {container.cend()}; + } + reverse_iterator rbegin() noexcept { return {container.rbegin()}; } @@ -202,6 +254,22 @@ namespace iter { return {container.rend()}; } + const_reverse_iterator rbegin() const noexcept { + return {container.rbegin()}; + } + + const_reverse_iterator rend() const noexcept { + return {container.rend()}; + } + + const_reverse_iterator crbegin() const noexcept { + return {container.rbegin()}; + } + + const_reverse_iterator crend() const noexcept { + return {container.rend()}; + } + // get() exposes the underlying container. this allows the // itertools to manipulate the iterators in the container // and should not be depended on anywhere else. From 7b22090f634203c49623596a2adf15ab2e298551 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 7 Apr 2015 23:08:44 -0700 Subject: [PATCH 1082/1866] updates permutations reqs --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9c3c12de..72e751bb 100644 --- a/README.md +++ b/README.md @@ -611,7 +611,8 @@ for (auto&& v : combinations_with_replacement(s, 2)) { permutations ----------- -Generates all the permutations of a range using `std::next_permutation` +Generates all the permutations of a range using `std::next_permutation`. The +iterators of the sequence passed must have an `operator*() const` Example usage: ```c++ From a6942eadd72f5617548f092ef34bfa187e363ea7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 16 Apr 2015 20:58:00 -0700 Subject: [PATCH 1083/1866] converts testrange to a set of examples --- examples/range_examples.cpp | 61 +++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 examples/range_examples.cpp diff --git a/examples/range_examples.cpp b/examples/range_examples.cpp new file mode 100644 index 00000000..a0e742ee --- /dev/null +++ b/examples/range_examples.cpp @@ -0,0 +1,61 @@ +#include + +#include + +int main() { + std::cout << "range(10): { "; + for (auto i : iter::range(10)) { + std::cout << i << ' '; + } + std::cout << "}\n"; + + // range works with a start and exclusive stop + std::cout << "range(20, 30): { "; + for (auto i : iter::range(20, 30)) { + std::cout << i << ' '; + } + std::cout << "}\n"; + + // range supports a step size (prints 50, 52 ... 58) + std::cout << "range(50, 60, 2): { "; + for (auto i : iter::range(50, 60, 2)) { + std::cout << i << ' '; + } + std::cout << "}\n"; + + // ranges can cover negative values + std::cout << "range(-10, 10, 2): { "; + for (auto i : iter::range(-10, 10, 2)) { + std::cout << i << ' '; + } + std::cout << "}\n"; + + // the step size doesn't need to evenly divide the distance + std::cout << "range(0, 5, 4): { "; + for (auto i : iter::range(0, 5, 4)) { + std::cout << i << ' '; + } + std::cout << "}\n"; + + // ranges can go down with a negative step + std::cout << "range(-1, -10, -2): { "; + for (auto i : iter::range(-1, -10, -2)) { + std::cout << i << ' '; + } + std::cout << "}\n"; + + // ranges can work with floats and other types that act like numbers + // the normal concerns with comparing floats still hold here + std::cout << "range(5.0, 9.9, 0.5): { "; + for (auto i : iter::range(5.0, 9.9, 0.5)) { + std::cout << i << ' '; + } + std::cout << "}\n"; + + // ranges of course support unsigned values + std::cout << "range(10u): { "; + for (auto i : iter::range(10u)) { + std::cout << i << ' '; + } + std::cout << "}\n"; +} From 1d1239803f6202e219ef51590654cc66f087d3b4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 16 Apr 2015 21:14:24 -0700 Subject: [PATCH 1084/1866] converts testenumerate into examples --- examples/enumerate_examples.cpp | 42 +++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 examples/enumerate_examples.cpp diff --git a/examples/enumerate_examples.cpp b/examples/enumerate_examples.cpp new file mode 100644 index 00000000..39786696 --- /dev/null +++ b/examples/enumerate_examples.cpp @@ -0,0 +1,42 @@ +#include + +#include +#include +#include +#include + + +int main() { + std::cout << "enumerating the characters of a string \"hello\":\n"; + const std::string const_string("hello"); + for (auto&& e : iter::enumerate(const_string)) { + std::cout << '(' << e.index << ", " << e.element << ") "; + } + std::cout << '\n'; + + std::vector vec = {20, 30, 50}; + std::cout << "enumerating a vector of {20, 30, 50}:\n"; + for (auto&& e : iter::enumerate(vec)) { + std::cout << '(' << e.index << ", " << e.element << ") "; + e.element = 0; + } + std::cout << '\n'; + assert(vec[0] == 0); + assert(vec[1] == 0); + assert(vec[2] == 0); + + // itertools supports raw arrays + std::cout << "statically sized arrays can be enumerated\n"; + int array[] = {1, 9, 8, 11}; + for (auto&& e : iter::enumerate(array)) { + std::cout << '(' << e.index << ", " << e.element << ") "; + } + std::cout << '\n'; + + // itertools supports temporaries + std::cout << "vector temporary of {5, 2}\n"; + for (auto&& e : iter::enumerate(std::vector(5,2))) { + std::cout << '(' << e.index << ", " << e.element << ") "; + } + std::cout << '\n'; +} From 9d23f2f0bcf8407f4aeb8b85eaa811157d27f698 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 16 Apr 2015 21:23:01 -0700 Subject: [PATCH 1085/1866] converts testaccumulate into examples --- examples/accumulate_examples.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 examples/accumulate_examples.cpp diff --git a/examples/accumulate_examples.cpp b/examples/accumulate_examples.cpp new file mode 100644 index 00000000..9d9a2f67 --- /dev/null +++ b/examples/accumulate_examples.cpp @@ -0,0 +1,22 @@ +#include +#include + +#include +#include + +int main() { + std::vector vec = {0, 1, 2, 3, 4, 5}; + // accumulate adds elements by default + std::cout << "accumulate({1, 2, 3, 4, 5}): { "; + for (auto i : iter::accumulate(vec)) { + std::cout << i << ' '; + } + std::cout << "}\n"; + + // accumulate with a lambda for subtraction + std::cout << "accumulate({1, 2, 3, 4, 5}, subtract): { "; + for (auto i : iter::accumulate(vec, [](int a, int b){return a - b;})) { + std::cout << i << ' '; + } + std::cout << "}\n"; +} From d50a93eb149d0aff2d4304d369d70c7fc9d322bc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 16 Apr 2015 22:01:15 -0700 Subject: [PATCH 1086/1866] replaces testzip with zip examples --- examples/zip_examples.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 examples/zip_examples.cpp diff --git a/examples/zip_examples.cpp b/examples/zip_examples.cpp new file mode 100644 index 00000000..0b7f347a --- /dev/null +++ b/examples/zip_examples.cpp @@ -0,0 +1,17 @@ +#include + +#include +#include +#include + +int main() { + std::vector ivec{1, 4, 9, 16, 25, 36}; + std::vector svec{"hello", "good day", "goodbye"}; + + // zip terminates on the shortest sequence, and is variadic + std::cout << "zipping a vector of ints and a vector of strings\n"; + for (auto&& e : iter::zip(ivec, svec)) { + std::cout << '(' << std::get<0>(e) << ", " << std::get<1>(e) << ")\n"; + } +} + From 54b1dd30b1a241efa95f1e075f1065ad4fb7b682 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 16 Apr 2015 22:15:57 -0700 Subject: [PATCH 1087/1866] replaces testchain with chain examples --- examples/chain_examples.cpp | 45 +++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 examples/chain_examples.cpp diff --git a/examples/chain_examples.cpp b/examples/chain_examples.cpp new file mode 100644 index 00000000..607fa040 --- /dev/null +++ b/examples/chain_examples.cpp @@ -0,0 +1,45 @@ +#include + +#include +#include +#include +#include +#include + +int main() { + // chaining combines two sequences for iteration + std::vector ivec = {1, 4, 7, 9}; + std::vector lvec = {100, 200, 300, 400, 500, 600}; + std::cout << "chaining two int vectors together:\n"; + for (auto&& e : iter::chain(ivec, lvec)) { + std::cout << e << ' '; + } + std::cout << '\n'; + + std::vector vec1 = {'c', 'h'}; + std::array arr1{{'a', 'i', 'n', 'i'}}; + std::string s{"ng different "}; + std::list lst = {'t', 'y', 'p', 'e', 's'}; + + // chain can mix different sequence types as long as the type yielded + // by their underlying iterators is *exactly* the same + std::cout << "mixing: "; + for (auto&& c : iter::chain(vec1, arr1, s, lst)) { + std::cout << c; + } + std::cout << '\n'; + + std::vector> matrix = { + {2, 4, 6}, + {8, 10, 12}, + {14, 16, 18} + }; + + // chain.from_iterable effectively flattens a sequence by one level + std::cout << "chain.from_iterable to flatten matrix:\n"; + for (auto&& i : iter::chain.from_iterable(matrix)) { + std::cout << i << ' '; + } + std::cout << '\n'; + +} From 1ed29ab234209efc5dfde01812bcbccb508cadba Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 17 Apr 2015 08:56:16 -0700 Subject: [PATCH 1088/1866] adds examples for all combinatorics --- examples/combinatoric_examples.cpp | 63 ++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 examples/combinatoric_examples.cpp diff --git a/examples/combinatoric_examples.cpp b/examples/combinatoric_examples.cpp new file mode 100644 index 00000000..d7111a56 --- /dev/null +++ b/examples/combinatoric_examples.cpp @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include + +#include +#include +#include + +int main() { + const std::vector v1 = {1,2,3,4,5}; + + std::cout << "combinations({1,2,3,4,5}, 3}:\n"; + for (auto&& ns : iter::combinations(v1,3)) { + std::cout << "{ "; + for (auto&& j : ns ) { + std::cout << j << ' '; + } + std::cout << "}\n"; + } + + + + // allows elements to be used repeatedly + std::cout << "combinations_with_replacement({1, 2}, 4):\n"; + std::vector v2 = {1,2}; + for (auto&& ns : iter::combinations_with_replacement(v2, 4)) { + std::cout << "{ "; + for (auto&& j : ns ) { + std::cout << j << ' '; + } + std::cout << "}\n"; + } + + std::cout << "permutations(\"abc\"):\n"; + std::string s{"abc"}; + for (auto&& cs : iter::permutations(s)) { + std::cout << "{ "; + for (auto&& c : cs ) { + std::cout << c << ' '; + } + std::cout << "}\n"; + } + + std::vector v3 = {"abc", "def"}; + std::cout << "product of three vectors (int, int, string):\n"; + for (auto&& t : iter::product(v1,v2,v3)) { + std::cout << "{ " + << std::get<0>(t) << ' ' + << std::get<1>(t) << ' ' + << std::get<2>(t) << " }\n"; + } + + std::cout << "powerset({1,2,3,4,5}):\n"; + for (auto&& ns : iter::powerset(v1)) { + std::cout << "{ "; + for (auto&& i : ns ) { + std::cout << i << ' '; + } + std::cout << "}\n"; + } +} From c295d8abf622aa8633b91c13b78165ca754f20a4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 18 Apr 2015 18:05:50 -0700 Subject: [PATCH 1089/1866] cycle_examples added --- examples/cycle_examples.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 examples/cycle_examples.cpp diff --git a/examples/cycle_examples.cpp b/examples/cycle_examples.cpp new file mode 100644 index 00000000..51eecafb --- /dev/null +++ b/examples/cycle_examples.cpp @@ -0,0 +1,29 @@ +#include + +#include +#include +#include + +int main() { + std::cout << "cycle({2, 4, 6}) run 20 times:\n"; + std::vector vec = {2, 4, 6}; + size_t count = 0; + for (auto&& i : iter::cycle(vec)) { + std::cout << i << '\n'; + if (count == 20) { + break; + } + ++count; + } + + std::cout << "cycle(\"hello\") run 20 times:\n"; + count = 0; + const std::string s("hello"); + for (auto&& c : iter::cycle(s)) { + std::cout << c << '\n'; + if (count == 20) { + break; + } + ++count; + } +} From 4628ea06c5e4f902257626105fa2d8c68cc4180d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 18 Apr 2015 18:38:07 -0700 Subject: [PATCH 1090/1866] adds slice_examples --- examples/slice_examples.cpp | 58 +++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 examples/slice_examples.cpp diff --git a/examples/slice_examples.cpp b/examples/slice_examples.cpp new file mode 100644 index 00000000..42a16e33 --- /dev/null +++ b/examples/slice_examples.cpp @@ -0,0 +1,58 @@ +#include + +#include +#include + +#include +#include + +int main() { + std::string a = "hello world"; + + std::cout << "a = { "; + for (auto&& i : a) { + std::cout << i << ' '; + } + std::cout << "}\n"; + + + // just like range(), the step doesn't have to make it end anywhere + // specific, below, the step is too great to cover more than two elements + std::cout << "slice(a, 1, 4, 7): { "; + for (auto&& i : iter::slice(a, 1, 4, 5)) { + std::cout << i << ' '; + } + std::cout << "\n"; + + std::cout << "slice(a, 2): { "; + for (auto&& i : iter::slice(a, 2)) { + std::cout << i << ' '; + } + std::cout << "}\n"; + + std::cout << "slice(a, 1, 5): { "; + for (auto&& i : iter::slice(a, 1, 5)) { + std::cout << i << ' '; + } + std::cout << "}\n"; + + std::cout << "slice(a, 2, 8, 2): { "; + for (auto&& i : iter::slice(a, 2, 8, 2)) { + std::cout << i << ' '; + } + std::cout << "}\n"; + + // the stop can be beyond the end + std::cout << "slice(a, 100): { "; + for (auto&& i : iter::slice(a, 100)) { + std::cout << i << ' '; + } + std::cout << "}\n"; + + // the start can too + std::cout << "slice(a, 100, 200): { "; + for (auto&& i : iter::slice(a, 100, 200)) { + std::cout << i << ' '; + } + std::cout << "}\n"; +} From b33ec175daab8f1a01c04ec9e4a638c5b0055e41 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 18 Apr 2015 19:07:00 -0700 Subject: [PATCH 1091/1866] adds compress examples --- examples/compress_examples.cpp | 43 ++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 examples/compress_examples.cpp diff --git a/examples/compress_examples.cpp b/examples/compress_examples.cpp new file mode 100644 index 00000000..b60197a9 --- /dev/null +++ b/examples/compress_examples.cpp @@ -0,0 +1,43 @@ +#include + +#include +#include + +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) { + using BVec = const std::vector; + + std::vector ns{0, 1, 2, 3, 4, 5}; + std::cout << "ns = { "; + for (auto&& i : ns) { + std::cout << i << ' '; + } + std::cout << "}\n"; + + BVec b1{true, false, true, false, true, false}; + + std::cout << "compress(ns, {true, false, true, false, true, false}): { "; + for (auto&& i : iter::compress(ns, b1)) { + std::cout << i << ' '; + } + std::cout << "}\n"; + + + BVec b2 {true}; + // compress terminates on the shortest sequence (either one) + std::cout << "compress(ns, {true}): { "; + for (auto&& i : iter::compress(ns, b2)) { + std::cout << i << ' '; + } + std::cout << "}\n"; + +} From 1d83d161b0a539b565b1563c9ae8c68e60e6ccc2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 18 Apr 2015 19:36:21 -0700 Subject: [PATCH 1092/1866] replaces testcount with count_examples --- examples/count_examples.cpp | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 examples/count_examples.cpp diff --git a/examples/count_examples.cpp b/examples/count_examples.cpp new file mode 100644 index 00000000..10ac8a72 --- /dev/null +++ b/examples/count_examples.cpp @@ -0,0 +1,37 @@ +#include + +#include + +int main() { + std::cout << "count() counts towards infinity, breaks at 10\n"; + for (auto i : iter::count()) { + std::cout << i << '\n'; + if (i == 10) { + break; + } + } + + std::cout << "count(20) starts counting from 20, breaks at 30\n"; + for (auto i : iter::count(20)) { + std::cout << i << '\n'; + if (i == 30) { + break; + } + } + + std::cout << "count(50, 2) counts by 2 starting at 50, breaks at 70\n"; + for (auto i : iter::count(50, 2)) { + std::cout << i << '\n'; + if (i >= 70) { + break; + } + } + + std::cout << "count(0, -1) counts down towards -infinity, breaks at -10\n"; + for (auto i : iter::count(0, -1)) { + std::cout << i << '\n'; + if (i == -10) { + break; + } + } +} From 535c0a620882920b1afcac4375fdcf50cb7d1dbd Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 18 Apr 2015 19:47:44 -0700 Subject: [PATCH 1093/1866] replaces testdropwhile with dropwhile_examples --- examples/dropwhile_examples.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 examples/dropwhile_examples.cpp diff --git a/examples/dropwhile_examples.cpp b/examples/dropwhile_examples.cpp new file mode 100644 index 00000000..8c628f1a --- /dev/null +++ b/examples/dropwhile_examples.cpp @@ -0,0 +1,19 @@ +#include + +#include +#include + + +int main() { + std::vector ns = {0, 1, 2, 3, 4, 5}; + std::cout << "ns = { "; + for (auto&& i : ns) { + std::cout << i << ' '; + } + std::cout << "}\n"; + + std::cout << "dropwhile elements are less than 5\n"; + for (auto&& i : iter::dropwhile([] (int i) {return i < 5;}, ns)) { + std::cout << i << '\n'; + } +} From 40255292c17713ecf867feb60a7f3c31edf67c8a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 18 Apr 2015 20:03:28 -0700 Subject: [PATCH 1094/1866] replaces testfilter with filter_examples --- examples/filter_examples.cpp | 58 ++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 examples/filter_examples.cpp diff --git a/examples/filter_examples.cpp b/examples/filter_examples.cpp new file mode 100644 index 00000000..d28c443a --- /dev/null +++ b/examples/filter_examples.cpp @@ -0,0 +1,58 @@ +#include + +#include +#include + +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 ns{1, 5, 6, 0, 7, 2, 3, 8, 3, 0, 2, 1}; + std::cout << "ns = { "; + for (auto&& i : ns) { + std::cout << i << ' '; + } + std::cout << "}\n"; + + std::cout << "Greater than 4 (function pointer)\n"; + for (auto&& i : iter::filter(greater_than_four, ns)) { + std::cout << i << '\n'; + } + + std::cout << "Less than 4 (lambda)\n"; + for (auto&& i : iter::filter([] (const int i) { return i < 4; }, ns)) { + std::cout << i << '\n'; + } + + LessThanValue lv(4); + std::cout << "Less than 4 (callable object)\n"; + for (auto&& i : iter::filter(lv, ns)) { + std::cout << i << '\n'; + } + + // filter(seq) with no predicate uses the truthiness of the values + std::cout << "Nonzero ints filter(ns)\n"; + for (auto&& i : iter::filter(ns)) { + std::cout << i << '\n'; + } + + std::cout << "odd numbers\n"; + for (auto&& i : iter::filter([] (const int i) {return i % 2;}, ns)) { + std::cout << i << '\n'; + } +} From 31d5da8dfc2b6e2ea477dc957e5d47e2c8311c87 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 18 Apr 2015 20:46:54 -0700 Subject: [PATCH 1095/1866] replaces testfilterfalse with filterfalse_examples --- examples/filterfalse_examples.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 examples/filterfalse_examples.cpp diff --git a/examples/filterfalse_examples.cpp b/examples/filterfalse_examples.cpp new file mode 100644 index 00000000..772005a8 --- /dev/null +++ b/examples/filterfalse_examples.cpp @@ -0,0 +1,29 @@ +#include + +#include +#include + +bool greater_than_four(int i) { + return i > 4; +} + +int main() { + std::vector ns{1, 5, 6, 0, 7, 2, 3, 8, 3, 0, 2, 1}; + std::cout << "ns = { "; + for (auto&& i : ns) { + std::cout << i << ' '; + } + std::cout << "}\n"; + + // like filter() but only shows elements that are false under the predicate + std::cout << "Greater than 4\n"; + for (auto&& i : iter::filterfalse(greater_than_four, ns)) { + std::cout << i << '\n'; + } + + // single argument version only shows falsey values + std::cout << "filterfalse(ns):\n"; + for (auto&& i : iter::filterfalse(ns)) { + std::cout << i << '\n'; + } +} From 16e7239ebad96291a410594c0282f27bdbfa0861 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 1 May 2015 18:53:27 -0700 Subject: [PATCH 1096/1866] replaces testgroupby with groupby examples --- examples/groupby_examples.cpp | 51 +++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 examples/groupby_examples.cpp diff --git a/examples/groupby_examples.cpp b/examples/groupby_examples.cpp new file mode 100644 index 00000000..e4ae4048 --- /dev/null +++ b/examples/groupby_examples.cpp @@ -0,0 +1,51 @@ +#include + +#include +#include +#include +#include + + +int main() { + auto len = std::mem_fn(&std::string::length); + std::vector vec = { + "hi", "ab", "ho", + "abc", "def", + "abcde", "efghi" + }; + + std::cout << "strings grouped by their length\n"; + for (auto&& gb : iter::groupby(vec, len)) { + std::cout << "key(" << gb.first << "): "; + for (auto&& s : gb.second) { + std::cout << s << " "; + } + std::cout << '\n'; + } + + // groups may be skipped entirely or partially consumed + std::cout << "skipping length of 3\n"; + for (auto&& gb : iter::groupby(vec, len)) { + if (gb.first == 3) { + continue; + } + std::cout << "key(" << gb.first << "): "; + for (auto&& s : gb.second) { + std::cout << s << " "; + } + std::cout << '\n'; + } + + + std::cout << "ints grouped by their value:\n"; + std::vector ivec = {5, 5, 6, 6, 19, 19, 19, 19, 69, 0, 10, 10}; + for (auto gb : iter::groupby(ivec)) { + std::cout << "key(" << gb.first << "): "; + for (auto s : gb.second) { + std::cout << s << " "; + } + std::cout << '\n'; + } +} + + From b9352fe91e828c30c157e28efc85f8f0205aea5d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 1 May 2015 18:57:55 -0700 Subject: [PATCH 1097/1866] replaces testgrouper with grouper examples --- examples/grouper_examples.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 examples/grouper_examples.cpp diff --git a/examples/grouper_examples.cpp b/examples/grouper_examples.cpp new file mode 100644 index 00000000..0ae6bb40 --- /dev/null +++ b/examples/grouper_examples.cpp @@ -0,0 +1,23 @@ +#include + +#include +#include + +int main() { + std::cout << "chunk size: 4\n"; + std::vector v {1,2,3,4,5,6,7,8,9}; + for (auto&& sec : iter::grouper(v, 4)) { + for (auto&& i : sec) { + std::cout << i << " "; + } + std::cout << '\n'; + } + + std::cout << "chunk size: 3\n"; + for (auto&& sec : iter::grouper(v,3)) { + for (auto&& i : sec) { + std::cout << i << " "; + } + std::cout << '\n'; + } +} From 18c8d22bf4d7dda91408fd01c135139b1c84932d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 1 May 2015 19:09:34 -0700 Subject: [PATCH 1098/1866] replaces testimap with imap examples --- examples/imap_examples.cpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 examples/imap_examples.cpp diff --git a/examples/imap_examples.cpp b/examples/imap_examples.cpp new file mode 100644 index 00000000..812281b6 --- /dev/null +++ b/examples/imap_examples.cpp @@ -0,0 +1,33 @@ +#include + +#include +#include + +int main() { + // applies the function on its way through the sequence + std::cout << "mapping i*i over [1, 7): "; + std::vector vec1 = {1, 2, 3, 4, 5, 6}; + for (auto i : iter::imap([] (int i) {return i * i; }, vec1)) { + std::cout << i << ' '; + } + std::cout << '\n'; + + // multiple sequences can be used, each iterator will be advanced + // f(a[0], b[0]) then f(a[1], b[1]) etc. + std::cout << "vector sum of <1, 2, ..., 6> and <10, 20, ..., 60>: "; + std::vector vec2 = {10, 20, 30, 40, 50, 60}; + for (auto i : iter::imap([] (int x, int y) { return x + y; }, vec1, vec2)) { + std::cout << i << ' '; + } + std::cout << '\n'; + + // it will terminate on the shortest sequence + std::cout << "vector sum of <1, 2, ..., 6>, <10, 20, ..., 60>, and " + "<100, 200, 300>: "; + std::vector vec3 = {100, 200, 300}; + for (auto i : iter::imap([] (int a, int b, int c) { return a + b + c; }, + vec1, vec2, vec3)) { + std::cout << i << ' '; + } + std::cout << '\n'; +} From a327d096a70bf62b7844f68c0fa740b272ce6280 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 May 2015 09:13:07 -0700 Subject: [PATCH 1099/1866] renamed testrange as range_examples --- examples/range_examples.cpp | 104 ++++++++++++++++++++++-------------- examples/testrange.cpp | 83 ---------------------------- 2 files changed, 63 insertions(+), 124 deletions(-) delete mode 100644 examples/testrange.cpp diff --git a/examples/range_examples.cpp b/examples/range_examples.cpp index a0e742ee..9404ae57 100644 --- a/examples/range_examples.cpp +++ b/examples/range_examples.cpp @@ -2,60 +2,82 @@ #include -int main() { - std::cout << "range(10): { "; - for (auto i : iter::range(10)) { - std::cout << i << ' '; +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 << "}\n"; - // range works with a start and exclusive stop - std::cout << "range(20, 30): { "; - for (auto i : iter::range(20, 30)) { - std::cout << i << ' '; + std::cout << "Negative Tests\n"; + for (auto i: range(-10, 0)) { + std::cout << i << std::endl; } - std::cout << "}\n"; - // range supports a step size (prints 50, 52 ... 58) - std::cout << "range(50, 60, 2): { "; - for (auto i : iter::range(50, 60, 2)) { - std::cout << i << ' '; + for (auto i : range(-10, 10, 2)) { + std::cout << i << std::endl; } - std::cout << "}\n"; - // ranges can cover negative values - std::cout << "range(-10, 10, 2): { "; - for (auto i : iter::range(-10, 10, 2)) { - std::cout << i << ' '; + std::cout << "Tests where (stop - start)%step != 0" << std::endl; + for (auto i : range(1, 10, 2)) { + std::cout << i << std::endl; } - std::cout << "}\n"; - // the step size doesn't need to evenly divide the distance - std::cout << "range(0, 5, 4): { "; - for (auto i : iter::range(0, 5, 4)) { - std::cout << i << ' '; + 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 << "}\n"; + 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; + } - // ranges can go down with a negative step - std::cout << "range(-1, -10, -2): { "; - for (auto i : iter::range(-1, -10, -2)) { - std::cout << i << ' '; + 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; } - std::cout << "}\n"; - // ranges can work with floats and other types that act like numbers - // the normal concerns with comparing floats still hold here - std::cout << "range(5.0, 9.9, 0.5): { "; - for (auto i : iter::range(5.0, 9.9, 0.5)) { - std::cout << i << ' '; + for (auto i : range(0, 1, -1)) { + std::cout << i << std::endl; } - std::cout << "}\n"; - // ranges of course support unsigned values - std::cout << "range(10u): { "; - for (auto i : iter::range(10u)) { - std::cout << i << ' '; + std::cout << "Should see exception now\n"; + for (auto i : range(0, 10, 0) ) { + std::cout << i << std::endl; } - std::cout << "}\n"; + + return 0; } diff --git a/examples/testrange.cpp b/examples/testrange.cpp deleted file mode 100644 index 9404ae57..00000000 --- a/examples/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; -} From 0673c8db80bf93fe26b6a85496e7470960bff505 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 May 2015 09:17:18 -0700 Subject: [PATCH 1100/1866] replaces testrepeat with repeat examples --- examples/repeat_examples.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 examples/repeat_examples.cpp diff --git a/examples/repeat_examples.cpp b/examples/repeat_examples.cpp new file mode 100644 index 00000000..24d37a8d --- /dev/null +++ b/examples/repeat_examples.cpp @@ -0,0 +1,22 @@ +#include + +#include + +int main () { + int a = 10; + int i = 0; + + std::cout << "repeat(10) breaks after 20: "; + for (auto&& num : iter::repeat(a)) { + std::cout << num << ' '; + ++i; + if (i >= 20) break; + } + std::cout << '\n'; + + std::cout << "repeat(" << a << ", 15): repeats 15 times: "; + for (auto&& num : iter::repeat(a,15)) { + std::cout << num << ' '; + } + std::cout << '\n'; +} From b7c75586ba5b1650b93db06c8daa496a44f35ad6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 May 2015 09:25:55 -0700 Subject: [PATCH 1101/1866] replaces testreversed with reversed examples --- examples/reversed_examples.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 examples/reversed_examples.cpp diff --git a/examples/reversed_examples.cpp b/examples/reversed_examples.cpp new file mode 100644 index 00000000..d4d804d9 --- /dev/null +++ b/examples/reversed_examples.cpp @@ -0,0 +1,29 @@ +#include + +#include +#include +#include + +int main () { + std::vector nums{1,2,3,4,5,6,7}; + std::vector words{"hey","how","are","you","doing"}; + + std::cout << "numbers reversed: "; + for (auto&& i : iter::reversed(nums)) { + std::cout << i << ' '; + } + std::cout << '\n'; + + std::cout << "greeting reversed: "; + for (auto&& s : iter::reversed(words)) { + std::cout << s << ' '; + } + std::cout << '\n'; + + std::cout << "statically sized array: "; + int arr[] = {1, 2, 3, 4, 5, 6, 7}; + for (auto&& i : iter::reversed(arr)) { + std::cout << i << ' '; + } + std::cout << '\n'; +} From 540d3b72e4d1528cc9a25285fc37b17ce66ffb2b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 May 2015 09:34:20 -0700 Subject: [PATCH 1102/1866] replaces testsliding_window with examples --- examples/sliding_window_examples.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 examples/sliding_window_examples.cpp diff --git a/examples/sliding_window_examples.cpp b/examples/sliding_window_examples.cpp new file mode 100644 index 00000000..3c0d39dd --- /dev/null +++ b/examples/sliding_window_examples.cpp @@ -0,0 +1,22 @@ +#include "sliding_window.hpp" + +#include +#include + +int main() { + std::vector v = {1,2,3,4,5,6,7,8,9}; + for (auto&& sec : iter::sliding_window(v,4)) { + for (auto&& i : sec) { + std::cout << i << ' '; + } + std::cout << '\n'; + } + + std::cout << "Empty when window size is > length\n"; + for (auto&& sec : iter::sliding_window({1,2,3}, 10)) { + for (auto&& i : sec) { + std::cout << i << ' '; + } + std::cout << '\n'; + } +} From 57b72235ade33a94a4b6a18c2e78db2ca7b858da Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 May 2015 09:46:13 -0700 Subject: [PATCH 1103/1866] replaces testsorted with sorted examples --- examples/sorted_examples.cpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 examples/sorted_examples.cpp diff --git a/examples/sorted_examples.cpp b/examples/sorted_examples.cpp new file mode 100644 index 00000000..109d137d --- /dev/null +++ b/examples/sorted_examples.cpp @@ -0,0 +1,33 @@ +#include + +#include +#include +#include +#include + +int main() { + std::vector vec = {19, 45, 32, 10, 0, 90, 15, 1, 7, 5, 6, 69}; + std::cout << "sorted(vector): "; + for (auto&& i : iter::sorted(vec)) { + std::cout << i << ' '; + } + std::cout << '\n'; + + std::cout << "sorted by last character: "; + std::vector svec = {"hello", "everyone", "thanks", "for", + "having", "me", "here", "today"}; + for (auto&& s : iter::sorted(svec, + [] (const std::string& s1, const std::string& s2) { + return *s1.rbegin() < *s2.rbegin();})) { + std::cout << s << ' '; + } + std::cout << '\n'; + + // works even if the container isn't sortable + std::cout << "unordered_set sorted: "; + std::unordered_set uset = {10, 1, 20, 4, 50, 3}; + for (auto&& i : iter::sorted(uset)) { + std::cout << i << ' '; + } + std::cout << '\n'; +} From 445bac2274db8aaf3f4f95e34e42ef87da3dddd1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 May 2015 09:57:00 -0700 Subject: [PATCH 1104/1866] replaces testtakewhile with takewhile examples --- examples/takewhile_examples.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 examples/takewhile_examples.cpp diff --git a/examples/takewhile_examples.cpp b/examples/takewhile_examples.cpp new file mode 100644 index 00000000..3062a141 --- /dev/null +++ b/examples/takewhile_examples.cpp @@ -0,0 +1,13 @@ +#include + +#include +#include + +int main() { + std::vector ivec{1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1}; + std::cout << "take ints as long as they are less than 5: "; + for (auto&& i : iter::takewhile([] (int i) {return i < 5;}, ivec)) { + std::cout << i << ' '; + } + std::cout << '\n'; +} From b6649e83e2d154131dde41f94bc5b5804a2820ef Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 May 2015 10:03:04 -0700 Subject: [PATCH 1105/1866] replaces testuniquejustseen with examples --- examples/unique_justseen_examples.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 examples/unique_justseen_examples.cpp diff --git a/examples/unique_justseen_examples.cpp b/examples/unique_justseen_examples.cpp new file mode 100644 index 00000000..878cd4f8 --- /dev/null +++ b/examples/unique_justseen_examples.cpp @@ -0,0 +1,20 @@ +#include + +#include +#include + +int main() { + std::cout << "omits consecutive duplicates: "; + std::vector v = {1,1,1,2,2,4,4,5,6,7,8,8,8,8,9,9}; + for (auto&& i : iter::unique_justseen(v)) { + std::cout << i << ' '; + } + std::cout << '\n'; + + std::cout << "doesn't omit non-consecutive duplicates: "; + std::vector v2 = {1,2,3,2,1,2,3}; + for (auto&& i : iter::unique_justseen(v2)) { + std::cout << i << ' '; + } + std::cout << '\n'; +} From 44347d4cd92381c5471bb960fa9378cca574db13 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 May 2015 10:15:56 -0700 Subject: [PATCH 1106/1866] replaces testzip_longest with zip_longest examples --- examples/zip_longest_examples.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 examples/zip_longest_examples.cpp diff --git a/examples/zip_longest_examples.cpp b/examples/zip_longest_examples.cpp new file mode 100644 index 00000000..1bbffbf8 --- /dev/null +++ b/examples/zip_longest_examples.cpp @@ -0,0 +1,29 @@ +#include + +#include +#include +#include +#include +#include + +// prints Just VALUE or Nothing +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 ivec = {1, 4, 9, 16, 25, 36}; + std::vector svec = {"hello", "good day", "goodbye"}; + + std::cout << "zipping a vector of strings with a vector of ints:\n"; + for (auto&& e : iter::zip_longest(ivec, svec)) { + std::cout << '(' << std::get<0>(e) << ", " + << std::get<1>(e) << ")\n"; + } +} From 09e3f323bbb0bf6b55b1aef554dc905ffa98df1d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 May 2015 10:26:31 -0700 Subject: [PATCH 1107/1866] replaces testcommand_chains with mixed examples --- examples/mixed_examples.cpp | 69 +++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 examples/mixed_examples.cpp diff --git a/examples/mixed_examples.cpp b/examples/mixed_examples.cpp new file mode 100644 index 00000000..08ff774b --- /dev/null +++ b/examples/mixed_examples.cpp @@ -0,0 +1,69 @@ +#include +#include + +#include +#include +#include +#include +#include + +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 : iter::zip_longest(iter::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 : iter::enumerate(iter::enumerate(str))) { (void)p; } + for (auto&& p : iter::enumerate(iter::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 : iter::zip(strvec, + iter::chain(iter::slice(vec1,2,6), + iter::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 : iter::sliding_window(iter::chain(vec1,vec2),4)) { + 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; + } +} From 4c8307fd0c0b0edb0439a3694ae49ab222ef8712 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 May 2015 10:30:39 -0700 Subject: [PATCH 1108/1866] removes old test files --- examples/testaccumulate.cpp | 35 ------ examples/testchain.cpp | 61 --------- examples/testchainfromiterable.cpp | 28 ----- examples/testcombinations.cpp | 75 ----------- .../testcombinations_with_replacement.cpp | 55 -------- examples/testcommand_chains.cpp | 78 ------------ examples/testcompress.cpp | 67 ---------- examples/testcount.cpp | 38 ------ examples/testcycle.cpp | 70 ----------- examples/testdropwhile.cpp | 35 ------ examples/testenumerate.cpp | 60 --------- examples/testfilter.cpp | 83 ------------ examples/testfilterfalse.cpp | 93 -------------- examples/testgroupby.cpp | 109 ---------------- examples/testgrouper.cpp | 51 -------- examples/testimap.cpp | 45 ------- examples/testpermutations.cpp | 60 --------- examples/testpowerset.cpp | 44 ------- examples/testproduct.cpp | 77 ------------ examples/testrepeat.cpp | 31 ----- examples/testreversed.cpp | 43 ------- examples/testslice.cpp | 81 ------------ examples/testsliding_window.cpp | 53 -------- examples/testsorted.cpp | 36 ------ examples/testtakewhile.cpp | 32 ----- examples/testunique_everseen.cpp | 41 ------ examples/testunique_justseen.cpp | 35 ------ examples/testzip.cpp | 118 ------------------ examples/testzip_longest.cpp | 96 -------------- tests/.gitignore | 5 - tests/SConstruct | 51 -------- tests/samples.hpp | 98 --------------- tests/testaccumulate.cpp | 33 ----- tests/testchain.cpp | 61 --------- 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/testtakewhile.cpp | 32 ----- tests/testunique_everseen.cpp | 41 ------ tests/testunique_justseen.cpp | 35 ------ tests/testzip.cpp | 118 ------------------ tests/testzip_longest.cpp | 96 -------------- 62 files changed, 3695 deletions(-) delete mode 100644 examples/testaccumulate.cpp delete mode 100644 examples/testchain.cpp delete mode 100644 examples/testchainfromiterable.cpp delete mode 100644 examples/testcombinations.cpp delete mode 100644 examples/testcombinations_with_replacement.cpp delete mode 100644 examples/testcommand_chains.cpp delete mode 100644 examples/testcompress.cpp delete mode 100644 examples/testcount.cpp delete mode 100644 examples/testcycle.cpp delete mode 100644 examples/testdropwhile.cpp delete mode 100644 examples/testenumerate.cpp delete mode 100644 examples/testfilter.cpp delete mode 100644 examples/testfilterfalse.cpp delete mode 100644 examples/testgroupby.cpp delete mode 100644 examples/testgrouper.cpp delete mode 100644 examples/testimap.cpp delete mode 100644 examples/testpermutations.cpp delete mode 100644 examples/testpowerset.cpp delete mode 100644 examples/testproduct.cpp delete mode 100644 examples/testrepeat.cpp delete mode 100644 examples/testreversed.cpp delete mode 100644 examples/testslice.cpp delete mode 100644 examples/testsliding_window.cpp delete mode 100644 examples/testsorted.cpp delete mode 100644 examples/testtakewhile.cpp delete mode 100644 examples/testunique_everseen.cpp delete mode 100644 examples/testunique_justseen.cpp delete mode 100644 examples/testzip.cpp delete mode 100644 examples/testzip_longest.cpp 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/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/examples/testaccumulate.cpp b/examples/testaccumulate.cpp deleted file mode 100644 index edf3d0a4..00000000 --- a/examples/testaccumulate.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include - -#include -#include - -int main() { - // accumulate with a lambda for subtraction - 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'; - } - - // using a range instead of a vector - for (auto v : iter::accumulate(iter::range(10), - [](int a, int b){return a - b;})) { - std::cout << v << '\n'; - } - - // using a range and the default summing behavior - 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/examples/testchain.cpp b/examples/testchain.cpp deleted file mode 100644 index 19ab374d..00000000 --- a/examples/testchain.cpp +++ /dev/null @@ -1,61 +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; - } - } - { - 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/examples/testchainfromiterable.cpp b/examples/testchainfromiterable.cpp deleted file mode 100644 index f4b6d599..00000000 --- a/examples/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/examples/testcombinations.cpp b/examples/testcombinations.cpp deleted file mode 100644 index ee444b90..00000000 --- a/examples/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/examples/testcompress.cpp b/examples/testcompress.cpp deleted file mode 100644 index 5197f3e2..00000000 --- a/examples/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/examples/testcount.cpp b/examples/testcount.cpp deleted file mode 100644 index 946d6841..00000000 --- a/examples/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/examples/testcycle.cpp b/examples/testcycle.cpp deleted file mode 100644 index 138692cc..00000000 --- a/examples/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/examples/testdropwhile.cpp b/examples/testdropwhile.cpp deleted file mode 100644 index 3140f81a..00000000 --- a/examples/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/examples/testenumerate.cpp b/examples/testenumerate.cpp deleted file mode 100644 index fcc1745c..00000000 --- a/examples/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/examples/testfilter.cpp b/examples/testfilter.cpp deleted file mode 100644 index e8af2aab..00000000 --- a/examples/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/examples/testfilterfalse.cpp b/examples/testfilterfalse.cpp deleted file mode 100644 index 9063d0bf..00000000 --- a/examples/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/examples/testgroupby.cpp b/examples/testgroupby.cpp deleted file mode 100644 index 9fc03ee3..00000000 --- a/examples/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/examples/testgrouper.cpp b/examples/testgrouper.cpp deleted file mode 100644 index b16ebc98..00000000 --- a/examples/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/examples/testimap.cpp b/examples/testimap.cpp deleted file mode 100644 index 3d6f38ca..00000000 --- a/examples/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/examples/testpermutations.cpp b/examples/testpermutations.cpp deleted file mode 100644 index a73a2a3b..00000000 --- a/examples/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/examples/testpowerset.cpp b/examples/testpowerset.cpp deleted file mode 100644 index 20ca0098..00000000 --- a/examples/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/examples/testproduct.cpp b/examples/testproduct.cpp deleted file mode 100644 index 22d132ec..00000000 --- a/examples/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/examples/testrepeat.cpp b/examples/testrepeat.cpp deleted file mode 100644 index b91fba03..00000000 --- a/examples/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/examples/testreversed.cpp b/examples/testreversed.cpp deleted file mode 100644 index c6d0ab46..00000000 --- a/examples/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/examples/testslice.cpp b/examples/testslice.cpp deleted file mode 100644 index eaf8e1ce..00000000 --- a/examples/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/examples/testsliding_window.cpp b/examples/testsliding_window.cpp deleted file mode 100644 index 16708db7..00000000 --- a/examples/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/examples/testsorted.cpp b/examples/testsorted.cpp deleted file mode 100644 index aed57d32..00000000 --- a/examples/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/examples/testtakewhile.cpp b/examples/testtakewhile.cpp deleted file mode 100644 index bec3aeae..00000000 --- a/examples/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/examples/testunique_everseen.cpp b/examples/testunique_everseen.cpp deleted file mode 100644 index 015adb7d..00000000 --- a/examples/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/examples/testunique_justseen.cpp b/examples/testunique_justseen.cpp deleted file mode 100644 index 8f454b6d..00000000 --- a/examples/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/examples/testzip.cpp b/examples/testzip.cpp deleted file mode 100644 index 76a95fd7..00000000 --- a/examples/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/examples/testzip_longest.cpp b/examples/testzip_longest.cpp deleted file mode 100644 index 63dc8fd0..00000000 --- a/examples/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< -#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 19ab374d..00000000 --- a/tests/testchain.cpp +++ /dev/null @@ -1,61 +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; - } - } - { - 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/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: Sat, 2 May 2015 10:30:49 -0700 Subject: [PATCH 1109/1866] replaces everseen test with examples --- examples/unique_everseen_examples.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 examples/unique_everseen_examples.cpp diff --git a/examples/unique_everseen_examples.cpp b/examples/unique_everseen_examples.cpp new file mode 100644 index 00000000..a670f0b1 --- /dev/null +++ b/examples/unique_everseen_examples.cpp @@ -0,0 +1,13 @@ +#include + +#include +#include + +int main() { + std::vector v {1,2,3,4,3,2,1,5,6,7,7,8,9,8,9,6}; + std::cout << "omits all duplicates: "; + for (auto&& i : iter::unique_everseen(v)) { + std::cout << i << ' '; + } + std::cout << '\n'; +} From efdd82da8ed5d1ce271ede8d17c097bce273ae24 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 May 2015 10:32:05 -0700 Subject: [PATCH 1110/1866] cuts down range examples --- examples/range_examples.cpp | 105 +++++++++++++++--------------------- 1 file changed, 42 insertions(+), 63 deletions(-) diff --git a/examples/range_examples.cpp b/examples/range_examples.cpp index 9404ae57..1dd03199 100644 --- a/examples/range_examples.cpp +++ b/examples/range_examples.cpp @@ -2,82 +2,61 @@ #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; +int main() { + // print [0, 10) + std::cout << "range(10): { "; + for (auto i : iter::range(10)) { + std::cout << i << ' '; } + std::cout << "}\n"; - std::cout << "Negative Tests\n"; - for (auto i: range(-10, 0)) { - std::cout << i << std::endl; + // print [20, 30) + std::cout << "range(20, 30): { "; + for (auto i : iter::range(20, 30)) { + std::cout << i << ' '; } + std::cout << "}\n"; - for (auto i : range(-10, 10, 2)) { - std::cout << i << std::endl; + // prints every second number in the range [50, 60) + std::cout << "range(50, 60, 2): { "; + for (auto i : iter::range(50, 60, 2)) { + std::cout << i << ' '; } + std::cout << "}\n"; - std::cout << "Tests where (stop - start)%step != 0" << std::endl; - for (auto i : range(1, 10, 2)) { - std::cout << i << std::endl; + // prints every second number in the range [-10, 10) + std::cout << "range(-10, 10, 2): { "; + for (auto i : iter::range(-10, 10, 2)) { + std::cout << i << ' '; } + std::cout << "}\n"; - 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; + // the step doesn't need to cause i to equal stop eventually + std::cout << "range(0, 5, 4): { "; + for (auto i : iter::range(0, 5, 4)) { + std::cout << i << ' '; } - 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 << "}\n"; - 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; + // ranges can count down as well as up + std::cout << "range(-1, -10, -2): { "; + for (auto i : iter::range(-1, -10, -2)) { + std::cout << i << ' '; } + std::cout << "}\n"; - for (auto i : range(0, 1, -1)) { - std::cout << i << std::endl; + // range works with floats and other types as well + // the usual concerns with float comparison come into play here + std::cout << "range(5.0, 9.9, 0.5): { "; + for(auto i : iter::range(5.0, 9.9, 0.5)) { + std::cout << i << ' '; } + std::cout << "}\n"; - std::cout << "Should see exception now\n"; - for (auto i : range(0, 10, 0) ) { - std::cout << i << std::endl; + // range also works with unsigned values + std::cout << "range(10u): { "; + for(auto i : iter::range(10u)){ + std::cout << i << ' '; } - - return 0; + std::cout << "}\n"; } From ae71f8da81653e83f5d9c95f99f73af1a6ddf5a1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 May 2015 10:33:30 -0700 Subject: [PATCH 1111/1866] moves a line --- examples/cycle_examples.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/cycle_examples.cpp b/examples/cycle_examples.cpp index 51eecafb..7f973d66 100644 --- a/examples/cycle_examples.cpp +++ b/examples/cycle_examples.cpp @@ -5,9 +5,10 @@ #include int main() { + size_t count = 0; + std::cout << "cycle({2, 4, 6}) run 20 times:\n"; std::vector vec = {2, 4, 6}; - size_t count = 0; for (auto&& i : iter::cycle(vec)) { std::cout << i << '\n'; if (count == 20) { From 7da524261a710fa6a07a7eeb353c93f87ce5bdfa Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 May 2015 10:33:46 -0700 Subject: [PATCH 1112/1866] makes sample operator* const --- examples/samples.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/samples.hpp b/examples/samples.hpp index 9faba373..690fb71f 100644 --- a/examples/samples.hpp +++ b/examples/samples.hpp @@ -60,7 +60,7 @@ namespace itertest { // for testing, iterator derefences to an int instead of // an int& - int operator*() /*const*/ { + int operator*() const { return *this->current; } From 1aa86424b0b81dfc1ad71d1243da2a597ee7683f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 May 2015 10:33:58 -0700 Subject: [PATCH 1113/1866] ignores examples executables --- examples/.gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/.gitignore b/examples/.gitignore index a77d502e..61b23b0e 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -1,5 +1,4 @@ *.o *.swp -test* -!test*.cpp +*_examples .sconsign.dblite From c17104c136679454e5cc56adbc19acae28df2122 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 2 May 2015 10:34:27 -0700 Subject: [PATCH 1114/1866] builds examples --- examples/SConstruct | 62 +++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/examples/SConstruct b/examples/SConstruct index 74195c1e..41acb956 100644 --- a/examples/SConstruct +++ b/examples/SConstruct @@ -13,39 +13,35 @@ env = Environment( # 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 - count - filterfalse - grouper - chain - chainfromiterable - groupby - sorted - unique_justseen - unique_everseen - command_chains - ''') +progs = Split( + ''' + accumulate + chain + combinatoric + compress + count + cycle + dropwhile + enumerate + filter + filterfalse + groupby + grouper + imap + range + repeat + reversed + slice + sliding_window + sorted + takewhile + unique_justseen + unique_everseen + zip + zip_longest + mixed + ''') for p in progs: - env.Program('test{0}.cpp'.format(p)) + env.Program('{0}_examples.cpp'.format(p)) From 3109230f96acbdd93f61753856ff89c3050910de Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 20 May 2015 00:00:04 -0700 Subject: [PATCH 1115/1866] renamed catchtest as test --- {catchtest => test}/.gitignore | 0 {catchtest => test}/SConstruct | 0 {catchtest => test}/catch.hpp | 0 {catchtest => test}/helpers.hpp | 0 {catchtest => test}/test_accumulate.cpp | 0 {catchtest => test}/test_chain.cpp | 0 {catchtest => test}/test_combinations.cpp | 0 {catchtest => test}/test_combinations_with_replacement.cpp | 0 {catchtest => test}/test_compress.cpp | 0 {catchtest => test}/test_count.cpp | 0 {catchtest => test}/test_cycle.cpp | 0 {catchtest => test}/test_dropwhile.cpp | 0 {catchtest => test}/test_enumerate.cpp | 0 {catchtest => test}/test_filter.cpp | 0 {catchtest => test}/test_filterfalse.cpp | 0 {catchtest => test}/test_groupby.cpp | 0 {catchtest => test}/test_grouper.cpp | 0 {catchtest => test}/test_helpers.cpp | 0 {catchtest => test}/test_imap.cpp | 0 {catchtest => test}/test_iteratoriterator.cpp | 0 {catchtest => test}/test_main.cpp | 0 {catchtest => test}/test_mixed.cpp | 0 {catchtest => test}/test_permutations.cpp | 0 {catchtest => test}/test_powerset.cpp | 0 {catchtest => test}/test_product.cpp | 0 {catchtest => test}/test_range.cpp | 0 {catchtest => test}/test_repeat.cpp | 0 {catchtest => test}/test_reversed.cpp | 0 {catchtest => test}/test_slice.cpp | 0 {catchtest => test}/test_sliding_window.cpp | 0 {catchtest => test}/test_sorted.cpp | 0 {catchtest => test}/test_takewhile.cpp | 0 {catchtest => test}/test_unique_everseen.cpp | 0 {catchtest => test}/test_unique_justseen.cpp | 0 {catchtest => test}/test_zip.cpp | 0 {catchtest => test}/test_zip_longest.cpp | 0 36 files changed, 0 insertions(+), 0 deletions(-) rename {catchtest => test}/.gitignore (100%) rename {catchtest => test}/SConstruct (100%) rename {catchtest => test}/catch.hpp (100%) rename {catchtest => test}/helpers.hpp (100%) rename {catchtest => test}/test_accumulate.cpp (100%) rename {catchtest => test}/test_chain.cpp (100%) rename {catchtest => test}/test_combinations.cpp (100%) rename {catchtest => test}/test_combinations_with_replacement.cpp (100%) rename {catchtest => test}/test_compress.cpp (100%) rename {catchtest => test}/test_count.cpp (100%) rename {catchtest => test}/test_cycle.cpp (100%) rename {catchtest => test}/test_dropwhile.cpp (100%) rename {catchtest => test}/test_enumerate.cpp (100%) rename {catchtest => test}/test_filter.cpp (100%) rename {catchtest => test}/test_filterfalse.cpp (100%) rename {catchtest => test}/test_groupby.cpp (100%) rename {catchtest => test}/test_grouper.cpp (100%) rename {catchtest => test}/test_helpers.cpp (100%) rename {catchtest => test}/test_imap.cpp (100%) rename {catchtest => test}/test_iteratoriterator.cpp (100%) rename {catchtest => test}/test_main.cpp (100%) rename {catchtest => test}/test_mixed.cpp (100%) rename {catchtest => test}/test_permutations.cpp (100%) rename {catchtest => test}/test_powerset.cpp (100%) rename {catchtest => test}/test_product.cpp (100%) rename {catchtest => test}/test_range.cpp (100%) rename {catchtest => test}/test_repeat.cpp (100%) rename {catchtest => test}/test_reversed.cpp (100%) rename {catchtest => test}/test_slice.cpp (100%) rename {catchtest => test}/test_sliding_window.cpp (100%) rename {catchtest => test}/test_sorted.cpp (100%) rename {catchtest => test}/test_takewhile.cpp (100%) rename {catchtest => test}/test_unique_everseen.cpp (100%) rename {catchtest => test}/test_unique_justseen.cpp (100%) rename {catchtest => test}/test_zip.cpp (100%) rename {catchtest => test}/test_zip_longest.cpp (100%) diff --git a/catchtest/.gitignore b/test/.gitignore similarity index 100% rename from catchtest/.gitignore rename to test/.gitignore diff --git a/catchtest/SConstruct b/test/SConstruct similarity index 100% rename from catchtest/SConstruct rename to test/SConstruct diff --git a/catchtest/catch.hpp b/test/catch.hpp similarity index 100% rename from catchtest/catch.hpp rename to test/catch.hpp diff --git a/catchtest/helpers.hpp b/test/helpers.hpp similarity index 100% rename from catchtest/helpers.hpp rename to test/helpers.hpp diff --git a/catchtest/test_accumulate.cpp b/test/test_accumulate.cpp similarity index 100% rename from catchtest/test_accumulate.cpp rename to test/test_accumulate.cpp diff --git a/catchtest/test_chain.cpp b/test/test_chain.cpp similarity index 100% rename from catchtest/test_chain.cpp rename to test/test_chain.cpp diff --git a/catchtest/test_combinations.cpp b/test/test_combinations.cpp similarity index 100% rename from catchtest/test_combinations.cpp rename to test/test_combinations.cpp diff --git a/catchtest/test_combinations_with_replacement.cpp b/test/test_combinations_with_replacement.cpp similarity index 100% rename from catchtest/test_combinations_with_replacement.cpp rename to test/test_combinations_with_replacement.cpp diff --git a/catchtest/test_compress.cpp b/test/test_compress.cpp similarity index 100% rename from catchtest/test_compress.cpp rename to test/test_compress.cpp diff --git a/catchtest/test_count.cpp b/test/test_count.cpp similarity index 100% rename from catchtest/test_count.cpp rename to test/test_count.cpp diff --git a/catchtest/test_cycle.cpp b/test/test_cycle.cpp similarity index 100% rename from catchtest/test_cycle.cpp rename to test/test_cycle.cpp diff --git a/catchtest/test_dropwhile.cpp b/test/test_dropwhile.cpp similarity index 100% rename from catchtest/test_dropwhile.cpp rename to test/test_dropwhile.cpp diff --git a/catchtest/test_enumerate.cpp b/test/test_enumerate.cpp similarity index 100% rename from catchtest/test_enumerate.cpp rename to test/test_enumerate.cpp diff --git a/catchtest/test_filter.cpp b/test/test_filter.cpp similarity index 100% rename from catchtest/test_filter.cpp rename to test/test_filter.cpp diff --git a/catchtest/test_filterfalse.cpp b/test/test_filterfalse.cpp similarity index 100% rename from catchtest/test_filterfalse.cpp rename to test/test_filterfalse.cpp diff --git a/catchtest/test_groupby.cpp b/test/test_groupby.cpp similarity index 100% rename from catchtest/test_groupby.cpp rename to test/test_groupby.cpp diff --git a/catchtest/test_grouper.cpp b/test/test_grouper.cpp similarity index 100% rename from catchtest/test_grouper.cpp rename to test/test_grouper.cpp diff --git a/catchtest/test_helpers.cpp b/test/test_helpers.cpp similarity index 100% rename from catchtest/test_helpers.cpp rename to test/test_helpers.cpp diff --git a/catchtest/test_imap.cpp b/test/test_imap.cpp similarity index 100% rename from catchtest/test_imap.cpp rename to test/test_imap.cpp diff --git a/catchtest/test_iteratoriterator.cpp b/test/test_iteratoriterator.cpp similarity index 100% rename from catchtest/test_iteratoriterator.cpp rename to test/test_iteratoriterator.cpp diff --git a/catchtest/test_main.cpp b/test/test_main.cpp similarity index 100% rename from catchtest/test_main.cpp rename to test/test_main.cpp diff --git a/catchtest/test_mixed.cpp b/test/test_mixed.cpp similarity index 100% rename from catchtest/test_mixed.cpp rename to test/test_mixed.cpp diff --git a/catchtest/test_permutations.cpp b/test/test_permutations.cpp similarity index 100% rename from catchtest/test_permutations.cpp rename to test/test_permutations.cpp diff --git a/catchtest/test_powerset.cpp b/test/test_powerset.cpp similarity index 100% rename from catchtest/test_powerset.cpp rename to test/test_powerset.cpp diff --git a/catchtest/test_product.cpp b/test/test_product.cpp similarity index 100% rename from catchtest/test_product.cpp rename to test/test_product.cpp diff --git a/catchtest/test_range.cpp b/test/test_range.cpp similarity index 100% rename from catchtest/test_range.cpp rename to test/test_range.cpp diff --git a/catchtest/test_repeat.cpp b/test/test_repeat.cpp similarity index 100% rename from catchtest/test_repeat.cpp rename to test/test_repeat.cpp diff --git a/catchtest/test_reversed.cpp b/test/test_reversed.cpp similarity index 100% rename from catchtest/test_reversed.cpp rename to test/test_reversed.cpp diff --git a/catchtest/test_slice.cpp b/test/test_slice.cpp similarity index 100% rename from catchtest/test_slice.cpp rename to test/test_slice.cpp diff --git a/catchtest/test_sliding_window.cpp b/test/test_sliding_window.cpp similarity index 100% rename from catchtest/test_sliding_window.cpp rename to test/test_sliding_window.cpp diff --git a/catchtest/test_sorted.cpp b/test/test_sorted.cpp similarity index 100% rename from catchtest/test_sorted.cpp rename to test/test_sorted.cpp diff --git a/catchtest/test_takewhile.cpp b/test/test_takewhile.cpp similarity index 100% rename from catchtest/test_takewhile.cpp rename to test/test_takewhile.cpp diff --git a/catchtest/test_unique_everseen.cpp b/test/test_unique_everseen.cpp similarity index 100% rename from catchtest/test_unique_everseen.cpp rename to test/test_unique_everseen.cpp diff --git a/catchtest/test_unique_justseen.cpp b/test/test_unique_justseen.cpp similarity index 100% rename from catchtest/test_unique_justseen.cpp rename to test/test_unique_justseen.cpp diff --git a/catchtest/test_zip.cpp b/test/test_zip.cpp similarity index 100% rename from catchtest/test_zip.cpp rename to test/test_zip.cpp diff --git a/catchtest/test_zip_longest.cpp b/test/test_zip_longest.cpp similarity index 100% rename from catchtest/test_zip_longest.cpp rename to test/test_zip_longest.cpp From 8b58b1d86762729126e5b2cc7c7a27c172e1475c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 20 May 2015 00:06:49 -0700 Subject: [PATCH 1116/1866] 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 1117/1866] 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 1118/1866] 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 1119/1866] 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 20058e13e34eb03afed590aab51b4bac54c57876 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 20 May 2015 10:21:15 -0700 Subject: [PATCH 1120/1866] only builds zip_longest and mixed when possible when boost/optional is available --- examples/SConstruct | 5 +++-- test/SConstruct | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/SConstruct b/examples/SConstruct index 41acb956..9710069b 100644 --- a/examples/SConstruct +++ b/examples/SConstruct @@ -38,10 +38,11 @@ progs = Split( unique_justseen unique_everseen zip - zip_longest - mixed ''') +if Configure(env).CheckCXXHeader('boost/optional.hpp'): + progs.append('zip_longest') + progs.append('mixed') for p in progs: env.Program('{0}_examples.cpp'.format(p)) diff --git a/test/SConstruct b/test/SConstruct index 615fb6d5..a9a54bce 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -42,13 +42,14 @@ progs = Split( unique_everseen unique_justseen zip - zip_longest iteratoriterator mixed helpers ''' ) +if Configure(env).CheckCXXHeader('boost/optional.hpp'): + progs.append('zip_longest') test_sources = ['test_{}.cpp'.format(p) for p in progs] From 99c9c40bcc8a89387b4834bffc6fae3940526192 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 20 May 2015 10:22:35 -0700 Subject: [PATCH 1121/1866] ignores scons temp and config files --- examples/.gitignore | 2 ++ test/.gitignore | 2 ++ 2 files changed, 4 insertions(+) diff --git a/examples/.gitignore b/examples/.gitignore index 61b23b0e..319fe583 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -2,3 +2,5 @@ *.swp *_examples .sconsign.dblite +config.log +.sconf_temp/ diff --git a/test/.gitignore b/test/.gitignore index c686c757..68c1db22 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -3,3 +3,5 @@ test_* !test_*.cpp .sconsign.dblite +config.log +.sconf_temp/ From 8fa94f7452cd28adc0007886630b3eae8174dec4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 20 May 2015 10:55:54 -0700 Subject: [PATCH 1122/1866] 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 1123/1866] 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 1124/1866] 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 1125/1866] 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 d3eca914a1d41e2fcd9fdd3f90bdb389361fc80b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 May 2015 15:23:52 -0700 Subject: [PATCH 1126/1866] general readme cleanup --- README.md | 218 ++++++++++++++++++++++++++---------------------------- 1 file changed, 106 insertions(+), 112 deletions(-) diff --git a/README.md b/README.md index 72e751bb..e8895623 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ appears as: ```c++ vector vec{2, 4, 6, 8}; -for (auto&& e : enumerate(vec)) { +for (auto&& e : enumerate(vec)) { cout << e.index << ": " << e.element @@ -152,33 +152,32 @@ Prints only zero values. for(auto&& i : filterfalse(vec)) { cout << i << '\n'; } + ``` unique_everseen --------------- -This is a filter adaptor that only generates values that have never been seen -before. For this algo to work your object must be specialized for `std::hash` -otherwise it will not be very efficient +This is a filter adaptor that only generates values that have never been seen +before. For this to work your object must be specialized for `std::hash`. -Example Usage: +Prints `1 2 3 4 5 6 7 8 9` ```c++ -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; +vector v {1,2,3,4,3,2,1,5,6,7,7,8,9,8,9,6}; +for (auto&& i : unique_everseen(v)) { + cout << i << ' '; +} ``` unique_justseen -------------- -Another filter adaptor that only prevents duplicates that are in a row, if the -sequence is sorted it will work exactly the same as `unique_justseen`, in that -case it will be better and more efficient to use. +Another filter adaptor that only omits consecutive duplicates. +Prints `1 2 3 4 3 2 1` Example Usage: ```c++ -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 << std::endl; +vector v {1,1,1,2,2,3,3,3,4,3,2,1,1,1}; +for (auto&& i : unique_justseen(v)) { + cout << i << ' '; +} ``` takewhile @@ -196,7 +195,7 @@ for (auto&& i : takewhile([] (int i) {return i < 5;}, ivec)) { dropwhile --------- -Yields all elements after and including the first element that is false under +Yields all elements after and including the first element that is true under the predicate. Prints `5 6 7 1 2` @@ -210,8 +209,8 @@ for (auto&& i : dropwhile([] (int i) {return i < 5;}, ivec)) { cycle ----- -Repeatedly produce all values of an iterable. The loop will be infinite, so a -`break` is necessary to exit. +Repeatedly produces all values of an iterable. The loop will be infinite, so a +`break` or other control flow structure is necessary to exit. Prints `1 2 3` repeatedly until `some_condition` is true ```c++ @@ -236,6 +235,7 @@ for (auto&& e : repeat(1, 5)) { cout << e << '\n'; } ``` + The below prints `2` forever ```c++ for (auto&& e : repeat(2)) { @@ -246,13 +246,13 @@ for (auto&& e : repeat(2)) { count ----- Effectively a `range` without a stopping point.
-`count()` with no arguments will start counting from 0 with a positive +`count()` with no arguments will start counting from 0 with a positive step of 1.
`count(i)` will start counting from `i` with a positive step of 1.
`count(i, st)` will start counting from `i` with a step of `st`. *Technical limitations*: Unlike Python which can use its long integer -types when needed, count() will eventually exceed the +types when needed, count() will eventually exceed the maximum possible value for its type (or minimum with a negative step). When using a signed type it is up to the API user to ensure this does not happen. If the limit is exceeded for signed types, the result is @@ -287,12 +287,12 @@ for (auto&& gb : groupby(vec, [] (const string &s) {return s.length(); })) { ``` *Note*: Just like Python's `itertools.groupby`, this doesn't do any sorting. It just iterates through, making a new group each time there is a key change. -Thus, if the the group is unsorted, the same key may appear multiple times. +Thus, if the group is unsorted, the same key may appear multiple times. accumulate ------- -Differs from `std::accumulate` (which in my humble opinion should be named -`std::reduce` or `std::foldl`). It is similar to a functional reduce where one +Differs from `std::accumulate` (which in my humble opinion should be named +`std::reduce` or `std::foldl`). It is similar to a functional reduce where one can see all of the intermediate results. By default, it keeps a running sum. Prints: `1 3 6 10 15` ```c++ @@ -300,7 +300,7 @@ for (auto&& i : accumulate(range(1, 6))) { cout << i << '\n'; } ``` -A second, optional argument may provide an alternative binary function +A second, optional argument may provide an alternative binary function to compute results. The following example multiplies the numbers, rather than adding them. Prints: `1 2 6 24 120` @@ -316,32 +316,31 @@ and assignment. 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 whatever elements -the iterators were holding. +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. Example usage: ```c++ -array i{{1,2,3,4}}; -vector f{1.2,1.4,12.3,4.5,9.9}; -vector s{"i","like","apples","alot","dude"}; -array d{{1.2,1.2,1.2,1.2,1.2}}; +array i{{1,2,3,4}}; +vector f{1.2,1.4,12.3,4.5,9.9}; +vector s{"i","like","apples","alot","dude"}; +array d{{1.2,1.2,1.2,1.2,1.2}}; -for (auto&& e : zip(i,f,s,d)) { - cout << std::get<0>(e) << ' ' - << std::get<1>(e) << ' ' - << std::get<2>(e) << ' ' - << std::get<3>(e) << '\n'; - std::get<1>(e)=2.2f; // modify the float array +for (auto&& e : zip(i,f,s,d)) { + cout << std::get<0>(e) << ' ' + << std::get<1>(e) << ' ' + << std::get<2>(e) << ' ' + << std::get<3>(e) << '\n'; + std::get<1>(e)=2.2f; // modifies the underlying 'f' array } ``` zip_longest ----------- Terminates on the longest sequence instead of the shortest. -Repeatedly yields a tuple of `boost::optional`s where `T` is the type +Repeatedly yields a tuple of `boost::optional`s where `T` is the type yielded by the sequences' respective iterators. Because of its boost dependency, `zip_longest` is not in `itertools.hpp` and must be included separately. @@ -402,7 +401,7 @@ for (auto&& i : imap([] (int x, int y) { return x + y; }, vec1, vec2)) { } ``` -*Note*: The name `imap` is chosen to prevent confusion/collision with +*Note*: The name `imap` is chosen to prevent confusion/collision with `std::map`, and because it is more related to `itertools.imap` than the python builtin `map`. @@ -427,7 +426,7 @@ sorted Allows iteration over a sequence in sorted order. `sorted` does **not** produce a new sequence, copy elements, or modify the original sequence. It only provides a way to iterate over existing elements. -`sorted` also takes an optional second +`sorted` also takes an optional second [comparator](http://en.cppreference.com/w/cpp/concept/Compare) argument. If not provided, defaults to `std::less`.
Iterables passed to sorted are required to have an iterator with @@ -449,12 +448,12 @@ This can chain any set of ranges together as long as their iterators dereference to the same type. ```c++ -vector empty{}; -vector vec1{1,2,3,4,5,6}; -array arr1{{7,8,9,10}}; +vector empty{}; +vector vec1{1,2,3,4,5,6}; +array arr1{{7,8,9,10}}; -for (auto&& i : chain(empty,vec1,arr1)) { - cout << i << '\n'; +for (auto&& i : chain(empty,vec1,arr1)) { + cout << i << '\n'; } ``` @@ -483,8 +482,8 @@ reversed Iterates over elements of a sequence in reverse order. ```c++ -for (auto&& i : reversed(a)) { - cout << i << '\n'; +for (auto&& i : reversed(a)) { + cout << i << '\n'; } ``` @@ -504,74 +503,70 @@ for (auto&& i : slice(a,0,15,3)) { sliding_window ------------- - -Takes a section from a range and increments the whole section. +Takes a section from a range and increments the whole section. Example: -`[1, 2, 3, 4, 5, 6, 7, 8, 9]` +`[1, 2, 3, 4, 5, 6, 7, 8, 9]` take a section of size 4, output is: ``` -1 2 3 4 -2 3 4 5 -3 4 5 6 -4 5 6 7 -5 6 7 8 -6 7 8 9 +1 2 3 4 +2 3 4 5 +3 4 5 6 +4 5 6 7 +5 6 7 8 +6 7 8 9 ``` Example Usage: ```c++ -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; - //has to be accessed with get if you want to store references - //because it is stored in a reference_wrapper (std::vector - //cannot hold references) - } - std::cout << std::endl; -} -``` +vector v = {1,2,3,4,5,6,7,8,9}; +for (auto&& sec : sliding_window(v,4)) { + for (auto&& i : sec) { + cout << i << ' '; + i.get() = 90; + } + cout << '\n'; +} +``` grouper ------ -grouper is very similar to sliding window, except instead of the +grouper is very similar to sliding window, except instead of the section sliding by only 1 it goes the length of the full section. Example usage: ```c++ -std::vector v {1,2,3,4,5,6,7,8,9}; -for (auto&& sec : grouper(v,4)) +vector v {1,2,3,4,5,6,7,8,9}; +for (auto&& sec : grouper(v,4)) //each section will have 4 elements //except the last one may be cut short { - for (auto&& i : sec) { - std::cout << i << " "; - i.get() *= 2; - } - std::cout << std::endl; -} + for (auto&& i : sec) { + cout << i << " "; + i.get() *= 2; + } + cout << '\n'; +} ``` product ------ -Generates the cartesian project of the given ranges put together +Generates the cartesian project of the given ranges put together -Example usage: +Example usage: ```c++ -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,v2,v3,v4)) { - std::cout << std::get<0>(t) << ", " - << std::get<1>(t) << ", " - << std::get<2>(t) << ", " - << std::get<3>(t) << std::endl; -} +vector v1{1,2,3}; +vector v2{7,8}; +vector v3{"the","cat"}; +vector v4{"hi","what","up","dude"}; +for (auto&& t : product(v1,v2,v3,v4)) { + cout << std::get<0>(t) << ", " + << std::get<1>(t) << ", " + << std::get<2>(t) << ", " + << std::get<3>(t) << '\n'; +} ``` combinations @@ -581,17 +576,16 @@ Generates n length unique sequences of the input range. Example usage: ```c++ -vector v = {1,2,3,4,5}; -for (auto&& i : combinations(v,3)) { - //cout << i << std::endl; - for (auto&& j : i ) cout << j << " "; - cout << '\n'; +vector v = {1,2,3,4,5}; +for (auto&& i : combinations(v,3)) { + for (auto&& j : i ) cout << j << " "; + cout << '\n'; } ``` combinations_with_replacement ----------------------------- -Like combinations, but with replacment of each element. The +Like combinations, but with replacement of each element. The below is printed by the loop that follows: ``` {A, A} @@ -616,27 +610,27 @@ iterators of the sequence passed must have an `operator*() const` Example usage: ```c++ -std::vector v = {1,2,3,4,5}; -for (auto&& vec : permutations(v)) { - for (auto&& i : vec) { - std::cout << i << " "; - } - std::cout << std::endl; -} +vector v = {1,2,3,4,5}; +for (auto&& vec : permutations(v)) { + for (auto&& i : vec) { + cout << i << ' '; + } + cout << '\n'; +} ``` powerset ------- -Generates every possible subset of a set, never run it since it runs in ðš¯(2^n). +Generates every possible subset of a set, runs in O(2^n). Example usage: ```c++ -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; +vector vec {1,2,3,4,5,6,7,8,9}; +for (auto&& v : powerset(vec)) { + for (auto&& i : v) { + cout << i << " "; + } + cout << '\n'; } ``` - - From 91201db3b6901ed75b1dc576cb05d4f7613615ed Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 May 2015 15:27:05 -0700 Subject: [PATCH 1127/1866] 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 3ffaca0d09b5c46321a5e8f1ae397ef99ad27c22 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 May 2015 18:01:27 -0700 Subject: [PATCH 1128/1866] removes catch from repo, adds download script scons will check to see if catch.hpp is available, and provide download instructions if its not ./download_catch.sh --- test/SConstruct | 15 +- test/catch.hpp | 9406 ---------------------------------------- test/download_catch.sh | 2 + 3 files changed, 14 insertions(+), 9409 deletions(-) delete mode 100644 test/catch.hpp create mode 100755 test/download_catch.sh diff --git a/test/SConstruct b/test/SConstruct index a9a54bce..350942bb 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -6,7 +6,7 @@ env = Environment( CXXFLAGS= ['-g', '-Wall', '-Wextra', '-pedantic', '-std=c++11', '-fdiagnostics-color=always', - '-I/usr/local/include'], + '-I/usr/local/include', '-I.'], CPPPATH='..', LINKFLAGS='-L/usr/local/lib') @@ -48,13 +48,22 @@ progs = Split( helpers ''' ) -if Configure(env).CheckCXXHeader('boost/optional.hpp'): + +conf = Configure(env) + +# if catch isn't available, exit +if not conf.CheckCXXHeader('catch.hpp'): + print("WARNING: catch.hpp not found, run ./download_catch.sh first") + Exit(1) + +if conf.CheckCXXHeader('boost/optional.hpp'): progs.append('zip_longest') +env = conf.Finish() + test_sources = ['test_{}.cpp'.format(p) for p in progs] for test_src in test_sources: env.Program([test_src, 'test_main.cpp']) env.Program('test_all', ['test_main.cpp'] + test_sources) - diff --git a/test/catch.hpp b/test/catch.hpp deleted file mode 100644 index c79324cf..00000000 --- a/test/catch.hpp +++ /dev/null @@ -1,9406 +0,0 @@ -/* - * CATCH v1.1 build 13 (develop branch) - * Generated: 2014-12-30 18:47:08.984634 - * ---------------------------------------------------------- - * This file has been merged from multiple headers. Please don't edit it directly - * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. - * - * Distributed under the Boost Software License, Version 1.0. (See accompanying - * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ -#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED -#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED - -#define TWOBLUECUBES_CATCH_HPP_INCLUDED - -// #included from: internal/catch_suppress_warnings.h - -#define TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED - -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wglobal-constructors" -#pragma clang diagnostic ignored "-Wvariadic-macros" -#pragma clang diagnostic ignored "-Wc99-extensions" -#pragma clang diagnostic ignored "-Wunused-variable" -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#pragma clang diagnostic ignored "-Wc++98-compat" -#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" -#elif defined __GNUC__ -#pragma GCC diagnostic ignored "-Wvariadic-macros" -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpadded" -#endif - -#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) -# define CATCH_IMPL -#endif - -#ifdef CATCH_IMPL -# ifndef CLARA_CONFIG_MAIN -# define CLARA_CONFIG_MAIN_NOT_DEFINED -# define CLARA_CONFIG_MAIN -# endif -#endif - -// #included from: internal/catch_notimplemented_exception.h -#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED - -// #included from: catch_common.h -#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED - -#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line -#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) -#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) - -#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr -#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) - -#include -#include -#include - -// #included from: catch_compiler_capabilities.h -#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED - -// Much of the following code is based on Boost (1.53) - -#ifdef __clang__ - -# if __has_feature(cxx_nullptr) -# define CATCH_CONFIG_CPP11_NULLPTR -# endif - -# if __has_feature(cxx_noexcept) -# define CATCH_CONFIG_CPP11_NOEXCEPT -# endif - -#endif // __clang__ - -//////////////////////////////////////////////////////////////////////////////// -// Borland -#ifdef __BORLANDC__ - -#if (__BORLANDC__ > 0x582 ) -//#define CATCH_CONFIG_SFINAE // Not confirmed -#endif - -#endif // __BORLANDC__ - -//////////////////////////////////////////////////////////////////////////////// -// EDG -#ifdef __EDG_VERSION__ - -#if (__EDG_VERSION__ > 238 ) -//#define CATCH_CONFIG_SFINAE // Not confirmed -#endif - -#endif // __EDG_VERSION__ - -//////////////////////////////////////////////////////////////////////////////// -// Digital Mars -#ifdef __DMC__ - -#if (__DMC__ > 0x840 ) -//#define CATCH_CONFIG_SFINAE // Not confirmed -#endif - -#endif // __DMC__ - -//////////////////////////////////////////////////////////////////////////////// -// GCC -#ifdef __GNUC__ - -#if __GNUC__ < 3 - -#if (__GNUC_MINOR__ >= 96 ) -//#define CATCH_CONFIG_SFINAE -#endif - -#elif __GNUC__ >= 3 - -// #define CATCH_CONFIG_SFINAE // Taking this out completely for now - -#endif // __GNUC__ < 3 - -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) ) - -#define CATCH_CONFIG_CPP11_NULLPTR -#endif - -#endif // __GNUC__ - -//////////////////////////////////////////////////////////////////////////////// -// Visual C++ -#ifdef _MSC_VER - -#if (_MSC_VER >= 1600) -#define CATCH_CONFIG_CPP11_NULLPTR -#endif - -#if (_MSC_VER >= 1310 ) // (VC++ 7.0+) -//#define CATCH_CONFIG_SFINAE // Not confirmed -#endif - -#endif // _MSC_VER - -// Use variadic macros if the compiler supports them -#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ - ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ - ( defined __GNUC__ && __GNUC__ >= 3 ) || \ - ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) - -#ifndef CATCH_CONFIG_NO_VARIADIC_MACROS -#define CATCH_CONFIG_VARIADIC_MACROS -#endif - -#endif - -//////////////////////////////////////////////////////////////////////////////// -// C++ language feature support - -// detect language version: -#if (__cplusplus == 201103L) -# define CATCH_CPP11 -# define CATCH_CPP11_OR_GREATER -#elif (__cplusplus >= 201103L) -# define CATCH_CPP11_OR_GREATER -#endif - -// noexcept support: -#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) -# define CATCH_NOEXCEPT noexcept -# define CATCH_NOEXCEPT_IS(x) noexcept(x) -#else -# define CATCH_NOEXCEPT throw() -# define CATCH_NOEXCEPT_IS(x) -#endif - -namespace Catch { - - class NonCopyable { -#ifdef CATCH_CPP11_OR_GREATER - NonCopyable( NonCopyable const& ) = delete; - NonCopyable( NonCopyable && ) = delete; - NonCopyable& operator = ( NonCopyable const& ) = delete; - NonCopyable& operator = ( NonCopyable && ) = delete; -#else - NonCopyable( NonCopyable const& info ); - NonCopyable& operator = ( NonCopyable const& ); -#endif - - protected: - NonCopyable() {} - virtual ~NonCopyable(); - }; - - class SafeBool { - public: - typedef void (SafeBool::*type)() const; - - static type makeSafe( bool value ) { - return value ? &SafeBool::trueValue : 0; - } - private: - void trueValue() const {} - }; - - template - inline void deleteAll( ContainerT& container ) { - typename ContainerT::const_iterator it = container.begin(); - typename ContainerT::const_iterator itEnd = container.end(); - for(; it != itEnd; ++it ) - delete *it; - } - template - inline void deleteAllValues( AssociativeContainerT& container ) { - typename AssociativeContainerT::const_iterator it = container.begin(); - typename AssociativeContainerT::const_iterator itEnd = container.end(); - for(; it != itEnd; ++it ) - delete it->second; - } - - bool startsWith( std::string const& s, std::string const& prefix ); - bool endsWith( std::string const& s, std::string const& suffix ); - bool contains( std::string const& s, std::string const& infix ); - void toLowerInPlace( std::string& s ); - std::string toLower( std::string const& s ); - std::string trim( std::string const& str ); - bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); - - struct pluralise { - pluralise( std::size_t count, std::string const& label ); - - friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); - - std::size_t m_count; - std::string m_label; - }; - - struct SourceLineInfo { - - SourceLineInfo(); - SourceLineInfo( char const* _file, std::size_t _line ); - SourceLineInfo( SourceLineInfo const& other ); -# ifdef CATCH_CPP11_OR_GREATER - SourceLineInfo( SourceLineInfo && ) = default; - SourceLineInfo& operator = ( SourceLineInfo const& ) = default; - SourceLineInfo& operator = ( SourceLineInfo && ) = default; -# endif - bool empty() const; - bool operator == ( SourceLineInfo const& other ) const; - - std::string file; - std::size_t line; - }; - - std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); - - // This is just here to avoid compiler warnings with macro constants and boolean literals - inline bool isTrue( bool value ){ return value; } - inline bool alwaysTrue() { return true; } - inline bool alwaysFalse() { return false; } - - void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); - - // Use this in variadic streaming macros to allow - // >> +StreamEndStop - // as well as - // >> stuff +StreamEndStop - struct StreamEndStop { - std::string operator+() { - return std::string(); - } - }; - template - T const& operator + ( T const& value, StreamEndStop ) { - return value; - } -} - -#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) -#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); - -#include - -namespace Catch { - - class NotImplementedException : public std::exception - { - public: - NotImplementedException( SourceLineInfo const& lineInfo ); - NotImplementedException( NotImplementedException const& ) {} - - virtual ~NotImplementedException() CATCH_NOEXCEPT {} - - virtual const char* what() const CATCH_NOEXCEPT; - - private: - std::string m_what; - SourceLineInfo m_lineInfo; - }; - -} // end namespace Catch - -/////////////////////////////////////////////////////////////////////////////// -#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) - -// #included from: internal/catch_context.h -#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED - -// #included from: catch_interfaces_generators.h -#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED - -#include - -namespace Catch { - - struct IGeneratorInfo { - virtual ~IGeneratorInfo(); - virtual bool moveNext() = 0; - virtual std::size_t getCurrentIndex() const = 0; - }; - - struct IGeneratorsForTest { - virtual ~IGeneratorsForTest(); - - virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; - virtual bool moveNext() = 0; - }; - - IGeneratorsForTest* createGeneratorsForTest(); - -} // end namespace Catch - -// #included from: catch_ptr.hpp -#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#endif - -namespace Catch { - - // An intrusive reference counting smart pointer. - // T must implement addRef() and release() methods - // typically implementing the IShared interface - template - class Ptr { - public: - Ptr() : m_p( NULL ){} - Ptr( T* p ) : m_p( p ){ - if( m_p ) - m_p->addRef(); - } - Ptr( Ptr const& other ) : m_p( other.m_p ){ - if( m_p ) - m_p->addRef(); - } - ~Ptr(){ - if( m_p ) - m_p->release(); - } - void reset() { - if( m_p ) - m_p->release(); - m_p = NULL; - } - Ptr& operator = ( T* p ){ - Ptr temp( p ); - swap( temp ); - return *this; - } - Ptr& operator = ( Ptr const& other ){ - Ptr temp( other ); - swap( temp ); - return *this; - } - void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } - T* get() { return m_p; } - const T* get() const{ return m_p; } - T& operator*() const { return *m_p; } - T* operator->() const { return m_p; } - bool operator !() const { return m_p == NULL; } - operator SafeBool::type() const { return SafeBool::makeSafe( m_p != NULL ); } - - private: - T* m_p; - }; - - struct IShared : NonCopyable { - virtual ~IShared(); - virtual void addRef() const = 0; - virtual void release() const = 0; - }; - - template - struct SharedImpl : T { - - SharedImpl() : m_rc( 0 ){} - - virtual void addRef() const { - ++m_rc; - } - virtual void release() const { - if( --m_rc == 0 ) - delete this; - } - - mutable unsigned int m_rc; - }; - -} // end namespace Catch - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -#include -#include -#include - -namespace Catch { - - class TestCase; - class Stream; - struct IResultCapture; - struct IRunner; - struct IGeneratorsForTest; - struct IConfig; - - struct IContext - { - virtual ~IContext(); - - virtual IResultCapture* getResultCapture() = 0; - virtual IRunner* getRunner() = 0; - virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; - virtual bool advanceGeneratorsForCurrentTest() = 0; - virtual Ptr getConfig() const = 0; - }; - - struct IMutableContext : IContext - { - virtual ~IMutableContext(); - virtual void setResultCapture( IResultCapture* resultCapture ) = 0; - virtual void setRunner( IRunner* runner ) = 0; - virtual void setConfig( Ptr const& config ) = 0; - }; - - IContext& getCurrentContext(); - IMutableContext& getCurrentMutableContext(); - void cleanUpContext(); - Stream createStream( std::string const& streamName ); - -} - -// #included from: internal/catch_test_registry.hpp -#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED - -// #included from: catch_interfaces_testcase.h -#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED - -#include - -namespace Catch { - - class TestSpec; - - struct ITestCase : IShared { - virtual void invoke () const = 0; - protected: - virtual ~ITestCase(); - }; - - class TestCase; - struct IConfig; - - struct ITestCaseRegistry { - virtual ~ITestCaseRegistry(); - virtual std::vector const& getAllTests() const = 0; - virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const = 0; - - }; -} - -namespace Catch { - -template -class MethodTestCase : public SharedImpl { - -public: - MethodTestCase( void (C::*method)() ) : m_method( method ) {} - - virtual void invoke() const { - C obj; - (obj.*m_method)(); - } - -private: - virtual ~MethodTestCase() {} - - void (C::*m_method)(); -}; - -typedef void(*TestFunction)(); - -struct NameAndDesc { - NameAndDesc( const char* _name = "", const char* _description= "" ) - : name( _name ), description( _description ) - {} - - const char* name; - const char* description; -}; - -struct AutoReg { - - AutoReg( TestFunction function, - SourceLineInfo const& lineInfo, - NameAndDesc const& nameAndDesc ); - - template - AutoReg( void (C::*method)(), - char const* className, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ) { - registerTestCase( new MethodTestCase( method ), - className, - nameAndDesc, - lineInfo ); - } - - void registerTestCase( ITestCase* testCase, - char const* className, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ); - - ~AutoReg(); - -private: - AutoReg( AutoReg const& ); - void operator= ( AutoReg const& ); -}; - -} // end namespace Catch - -#ifdef CATCH_CONFIG_VARIADIC_MACROS - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_TESTCASE( ... ) \ - static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\ - static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() - - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } - - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\ - namespace{ \ - struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ - void test(); \ - }; \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ - } \ - void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() - -#else - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ - static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\ - static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() - - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } - - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ - namespace{ \ - struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ - void test(); \ - }; \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ - } \ - void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() - -#endif - -// #included from: internal/catch_capture.hpp -#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED - -// #included from: catch_result_builder.h -#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED - -// #included from: catch_result_type.h -#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED - -namespace Catch { - - // ResultWas::OfType enum - struct ResultWas { enum OfType { - Unknown = -1, - Ok = 0, - Info = 1, - Warning = 2, - - FailureBit = 0x10, - - ExpressionFailed = FailureBit | 1, - ExplicitFailure = FailureBit | 2, - - Exception = 0x100 | FailureBit, - - ThrewException = Exception | 1, - DidntThrowException = Exception | 2, - - FatalErrorCondition = 0x200 | FailureBit - - }; }; - - inline bool isOk( ResultWas::OfType resultType ) { - return ( resultType & ResultWas::FailureBit ) == 0; - } - inline bool isJustInfo( int flags ) { - return flags == ResultWas::Info; - } - - // ResultDisposition::Flags enum - struct ResultDisposition { enum Flags { - Normal = 0x00, - - ContinueOnFailure = 0x01, // Failures fail test, but execution continues - FalseTest = 0x02, // Prefix expression with ! - SuppressFail = 0x04 // Failures are reported but do not fail the test - }; }; - - inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { - return static_cast( static_cast( lhs ) | static_cast( rhs ) ); - } - - inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } - inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } - inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } - -} // end namespace Catch - -// #included from: catch_assertionresult.h -#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED - -#include - -namespace Catch { - - struct AssertionInfo - { - AssertionInfo() {} - AssertionInfo( std::string const& _macroName, - SourceLineInfo const& _lineInfo, - std::string const& _capturedExpression, - ResultDisposition::Flags _resultDisposition ); - - std::string macroName; - SourceLineInfo lineInfo; - std::string capturedExpression; - ResultDisposition::Flags resultDisposition; - }; - - struct AssertionResultData - { - AssertionResultData() : resultType( ResultWas::Unknown ) {} - - std::string reconstructedExpression; - std::string message; - ResultWas::OfType resultType; - }; - - class AssertionResult { - public: - AssertionResult(); - AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); - ~AssertionResult(); -# ifdef CATCH_CPP11_OR_GREATER - AssertionResult( AssertionResult const& ) = default; - AssertionResult( AssertionResult && ) = default; - AssertionResult& operator = ( AssertionResult const& ) = default; - AssertionResult& operator = ( AssertionResult && ) = default; -# endif - - bool isOk() const; - bool succeeded() const; - ResultWas::OfType getResultType() const; - bool hasExpression() const; - bool hasMessage() const; - std::string getExpression() const; - std::string getExpressionInMacro() const; - bool hasExpandedExpression() const; - std::string getExpandedExpression() const; - std::string getMessage() const; - SourceLineInfo getSourceInfo() const; - std::string getTestMacroName() const; - - protected: - AssertionInfo m_info; - AssertionResultData m_resultData; - }; - -} // end namespace Catch - -namespace Catch { - - struct TestFailureException{}; - - template class ExpressionLhs; - - struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; - - struct CopyableStream { - CopyableStream() {} - CopyableStream( CopyableStream const& other ) { - oss << other.oss.str(); - } - CopyableStream& operator=( CopyableStream const& other ) { - oss.str(""); - oss << other.oss.str(); - return *this; - } - std::ostringstream oss; - }; - - class ResultBuilder { - public: - ResultBuilder( char const* macroName, - SourceLineInfo const& lineInfo, - char const* capturedExpression, - ResultDisposition::Flags resultDisposition ); - - template - ExpressionLhs operator->* ( T const& operand ); - ExpressionLhs operator->* ( bool value ); - - template - ResultBuilder& operator << ( T const& value ) { - m_stream.oss << value; - return *this; - } - - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); - - ResultBuilder& setResultType( ResultWas::OfType result ); - ResultBuilder& setResultType( bool result ); - ResultBuilder& setLhs( std::string const& lhs ); - ResultBuilder& setRhs( std::string const& rhs ); - ResultBuilder& setOp( std::string const& op ); - - void endExpression(); - - std::string reconstructExpression() const; - AssertionResult build() const; - - void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); - void captureResult( ResultWas::OfType resultType ); - void captureExpression(); - void react(); - bool shouldDebugBreak() const; - bool allowThrows() const; - - private: - AssertionInfo m_assertionInfo; - AssertionResultData m_data; - struct ExprComponents { - ExprComponents() : testFalse( false ) {} - bool testFalse; - std::string lhs, rhs, op; - } m_exprComponents; - CopyableStream m_stream; - - bool m_shouldDebugBreak; - bool m_shouldThrow; - }; - -} // namespace Catch - -// Include after due to circular dependency: -// #included from: catch_expression_lhs.hpp -#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED - -// #included from: catch_evaluate.hpp -#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4389) // '==' : signed/unsigned mismatch -#endif - -#include - -namespace Catch { -namespace Internal { - - enum Operator { - IsEqualTo, - IsNotEqualTo, - IsLessThan, - IsGreaterThan, - IsLessThanOrEqualTo, - IsGreaterThanOrEqualTo - }; - - template struct OperatorTraits { static const char* getName(){ return "*error*"; } }; - template<> struct OperatorTraits { static const char* getName(){ return "=="; } }; - template<> struct OperatorTraits { static const char* getName(){ return "!="; } }; - template<> struct OperatorTraits { static const char* getName(){ return "<"; } }; - template<> struct OperatorTraits { static const char* getName(){ return ">"; } }; - template<> struct OperatorTraits { static const char* getName(){ return "<="; } }; - template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; - - template - inline T& opCast(T const& t) { return const_cast(t); } - -// nullptr_t support based on pull request #154 from Konstantin Baumann -#ifdef CATCH_CONFIG_CPP11_NULLPTR - inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } -#endif // CATCH_CONFIG_CPP11_NULLPTR - - // So the compare overloads can be operator agnostic we convey the operator as a template - // enum, which is used to specialise an Evaluator for doing the comparison. - template - class Evaluator{}; - - template - struct Evaluator { - static bool evaluate( T1 const& lhs, T2 const& rhs) { - return opCast( lhs ) == opCast( rhs ); - } - }; - template - struct Evaluator { - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return opCast( lhs ) != opCast( rhs ); - } - }; - template - struct Evaluator { - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return opCast( lhs ) < opCast( rhs ); - } - }; - template - struct Evaluator { - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return opCast( lhs ) > opCast( rhs ); - } - }; - template - struct Evaluator { - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return opCast( lhs ) >= opCast( rhs ); - } - }; - template - struct Evaluator { - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return opCast( lhs ) <= opCast( rhs ); - } - }; - - template - bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { - return Evaluator::evaluate( lhs, rhs ); - } - - // This level of indirection allows us to specialise for integer types - // to avoid signed/ unsigned warnings - - // "base" overload - template - bool compare( T1 const& lhs, T2 const& rhs ) { - return Evaluator::evaluate( lhs, rhs ); - } - - // unsigned X to int - template bool compare( unsigned int lhs, int rhs ) { - return applyEvaluator( lhs, static_cast( rhs ) ); - } - template bool compare( unsigned long lhs, int rhs ) { - return applyEvaluator( lhs, static_cast( rhs ) ); - } - template bool compare( unsigned char lhs, int rhs ) { - return applyEvaluator( lhs, static_cast( rhs ) ); - } - - // unsigned X to long - template bool compare( unsigned int lhs, long rhs ) { - return applyEvaluator( lhs, static_cast( rhs ) ); - } - template bool compare( unsigned long lhs, long rhs ) { - return applyEvaluator( lhs, static_cast( rhs ) ); - } - template bool compare( unsigned char lhs, long rhs ) { - return applyEvaluator( lhs, static_cast( rhs ) ); - } - - // int to unsigned X - template bool compare( int lhs, unsigned int rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( int lhs, unsigned long rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( int lhs, unsigned char rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - - // long to unsigned X - template bool compare( long lhs, unsigned int rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( long lhs, unsigned long rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( long lhs, unsigned char rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - - // pointer to long (when comparing against NULL) - template bool compare( long lhs, T* rhs ) { - return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); - } - template bool compare( T* lhs, long rhs ) { - return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); - } - - // pointer to int (when comparing against NULL) - template bool compare( int lhs, T* rhs ) { - return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); - } - template bool compare( T* lhs, int rhs ) { - return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); - } - -#ifdef CATCH_CONFIG_CPP11_NULLPTR - // pointer to nullptr_t (when comparing against nullptr) - template bool compare( std::nullptr_t, T* rhs ) { - return Evaluator::evaluate( NULL, rhs ); - } - template bool compare( T* lhs, std::nullptr_t ) { - return Evaluator::evaluate( lhs, NULL ); - } -#endif // CATCH_CONFIG_CPP11_NULLPTR - -} // end of namespace Internal -} // end of namespace Catch - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -// #included from: catch_tostring.h -#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED - -// #included from: catch_sfinae.hpp -#define TWOBLUECUBES_CATCH_SFINAE_HPP_INCLUDED - -// Try to detect if the current compiler supports SFINAE - -namespace Catch { - - struct TrueType { - static const bool value = true; - typedef void Enable; - char sizer[1]; - }; - struct FalseType { - static const bool value = false; - typedef void Disable; - char sizer[2]; - }; - -#ifdef CATCH_CONFIG_SFINAE - - template struct NotABooleanExpression; - - template struct If : NotABooleanExpression {}; - template<> struct If : TrueType {}; - template<> struct If : FalseType {}; - - template struct SizedIf; - template<> struct SizedIf : TrueType {}; - template<> struct SizedIf : FalseType {}; - -#endif // CATCH_CONFIG_SFINAE - -} // end namespace Catch - -#include -#include -#include -#include -#include - -#ifdef __OBJC__ -// #included from: catch_objc_arc.hpp -#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED - -#import - -#ifdef __has_feature -#define CATCH_ARC_ENABLED __has_feature(objc_arc) -#else -#define CATCH_ARC_ENABLED 0 -#endif - -void arcSafeRelease( NSObject* obj ); -id performOptionalSelector( id obj, SEL sel ); - -#if !CATCH_ARC_ENABLED -inline void arcSafeRelease( NSObject* obj ) { - [obj release]; -} -inline id performOptionalSelector( id obj, SEL sel ) { - if( [obj respondsToSelector: sel] ) - return [obj performSelector: sel]; - return nil; -} -#define CATCH_UNSAFE_UNRETAINED -#define CATCH_ARC_STRONG -#else -inline void arcSafeRelease( NSObject* ){} -inline id performOptionalSelector( id obj, SEL sel ) { -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-performSelector-leaks" -#endif - if( [obj respondsToSelector: sel] ) - return [obj performSelector: sel]; -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - return nil; -} -#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained -#define CATCH_ARC_STRONG __strong -#endif - -#endif - -#ifdef CATCH_CPP11_OR_GREATER -#include -#include -#endif - -namespace Catch { - -// Why we're here. -template -std::string toString( T const& value ); - -// Built in overloads - -std::string toString( std::string const& value ); -std::string toString( std::wstring const& value ); -std::string toString( const char* const value ); -std::string toString( char* const value ); -std::string toString( const wchar_t* const value ); -std::string toString( wchar_t* const value ); -std::string toString( int value ); -std::string toString( unsigned long value ); -std::string toString( unsigned int value ); -std::string toString( const double value ); -std::string toString( const float value ); -std::string toString( bool value ); -std::string toString( char value ); -std::string toString( signed char value ); -std::string toString( unsigned char value ); - -#ifdef CATCH_CONFIG_CPP11_NULLPTR -std::string toString( std::nullptr_t ); -#endif - -#ifdef __OBJC__ - std::string toString( NSString const * const& nsstring ); - std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); - std::string toString( NSObject* const& nsObject ); -#endif - -namespace Detail { - - extern std::string unprintableString; - -// SFINAE is currently disabled by default for all compilers. -// If the non SFINAE version of IsStreamInsertable is ambiguous for you -// and your compiler supports SFINAE, try #defining CATCH_CONFIG_SFINAE -#ifdef CATCH_CONFIG_SFINAE - - template - class IsStreamInsertableHelper { - template struct TrueIfSizeable : TrueType {}; - - template - static TrueIfSizeable dummy(T2*); - static FalseType dummy(...); - - public: - typedef SizedIf type; - }; - - template - struct IsStreamInsertable : IsStreamInsertableHelper::type {}; - -#else - - struct BorgType { - template BorgType( T const& ); - }; - - TrueType& testStreamable( std::ostream& ); - FalseType testStreamable( FalseType ); - - FalseType operator<<( std::ostream const&, BorgType const& ); - - template - struct IsStreamInsertable { - static std::ostream &s; - static T const&t; - enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; - }; - -#endif - -#if defined(CATCH_CPP11_OR_GREATER) - template::value - > - struct EnumStringMaker - { - static std::string convert( T const& ) { return unprintableString; } - }; - - template - struct EnumStringMaker - { - static std::string convert( T const& v ) - { - return ::Catch::toString( - static_cast::type>(v) - ); - } - }; -#endif - template - struct StringMakerBase { -#if defined(CATCH_CPP11_OR_GREATER) - template - static std::string convert( T const& v ) - { - return EnumStringMaker::convert( v ); - } -#else - template - static std::string convert( T const& ) { return unprintableString; } -#endif - }; - - template<> - struct StringMakerBase { - template - static std::string convert( T const& _value ) { - std::ostringstream oss; - oss << _value; - return oss.str(); - } - }; - - std::string rawMemoryToString( const void *object, std::size_t size ); - - template - inline std::string rawMemoryToString( const T& object ) { - return rawMemoryToString( &object, sizeof(object) ); - } - -} // end namespace Detail - -template -struct StringMaker : - Detail::StringMakerBase::value> {}; - -template -struct StringMaker { - template - static std::string convert( U* p ) { - if( !p ) - return INTERNAL_CATCH_STRINGIFY( NULL ); - else - return Detail::rawMemoryToString( p ); - } -}; - -template -struct StringMaker { - static std::string convert( R C::* p ) { - if( !p ) - return INTERNAL_CATCH_STRINGIFY( NULL ); - else - return Detail::rawMemoryToString( p ); - } -}; - -namespace Detail { - template - std::string rangeToString( InputIterator first, InputIterator last ); -} - -//template -//struct StringMaker > { -// static std::string convert( std::vector const& v ) { -// return Detail::rangeToString( v.begin(), v.end() ); -// } -//}; - -template -std::string toString( std::vector const& v ) { - return Detail::rangeToString( v.begin(), v.end() ); -} - -#ifdef CATCH_CPP11_OR_GREATER -//toString for tuples - -namespace TupleDetail { - template< - typename Tuple, - std::size_t N = 0, - bool = (N < std::tuple_size::value) - > - struct ElementPrinter { - static void print( const Tuple& tuple, std::ostream& os ) - { - os << ( N ? ", " : " " ) - << Catch::toString(std::get(tuple)); - ElementPrinter::print(tuple,os); - } - }; - - template< - typename Tuple, - std::size_t N - > - struct ElementPrinter { - static void print( const Tuple&, std::ostream& ) {} - }; - -} - -template -struct StringMaker> { - - static std::string convert( const std::tuple& tuple ) - { - std::ostringstream os; - os << '{'; - TupleDetail::ElementPrinter>::print( tuple, os ); - os << " }"; - return os.str(); - } -}; -#endif - -namespace Detail { - template - std::string makeString( T const& value ) { - return StringMaker::convert( value ); - } -} // end namespace Detail - -/// \brief converts any type to a string -/// -/// The default template forwards on to ostringstream - except when an -/// ostringstream overload does not exist - in which case it attempts to detect -/// that and writes {?}. -/// Overload (not specialise) this template for custom typs that you don't want -/// to provide an ostream overload for. -template -std::string toString( T const& value ) { - return StringMaker::convert( value ); -} - - namespace Detail { - template - std::string rangeToString( InputIterator first, InputIterator last ) { - std::ostringstream oss; - oss << "{ "; - if( first != last ) { - oss << Catch::toString( *first ); - for( ++first ; first != last ; ++first ) - oss << ", " << Catch::toString( *first ); - } - oss << " }"; - return oss.str(); - } -} - -} // end namespace Catch - -namespace Catch { - -// Wraps the LHS of an expression and captures the operator and RHS (if any) - -// wrapping them all in a ResultBuilder object -template -class ExpressionLhs { - ExpressionLhs& operator = ( ExpressionLhs const& ); -# ifdef CATCH_CPP11_OR_GREATER - ExpressionLhs& operator = ( ExpressionLhs && ) = delete; -# endif - -public: - ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {} -# ifdef CATCH_CPP11_OR_GREATER - ExpressionLhs( ExpressionLhs const& ) = default; - ExpressionLhs( ExpressionLhs && ) = default; -# endif - - template - ResultBuilder& operator == ( RhsT const& rhs ) { - return captureExpression( rhs ); - } - - template - ResultBuilder& operator != ( RhsT const& rhs ) { - return captureExpression( rhs ); - } - - template - ResultBuilder& operator < ( RhsT const& rhs ) { - return captureExpression( rhs ); - } - - template - ResultBuilder& operator > ( RhsT const& rhs ) { - return captureExpression( rhs ); - } - - template - ResultBuilder& operator <= ( RhsT const& rhs ) { - return captureExpression( rhs ); - } - - template - ResultBuilder& operator >= ( RhsT const& rhs ) { - return captureExpression( rhs ); - } - - ResultBuilder& operator == ( bool rhs ) { - return captureExpression( rhs ); - } - - ResultBuilder& operator != ( bool rhs ) { - return captureExpression( rhs ); - } - - void endExpression() { - bool value = m_lhs ? true : false; - m_rb - .setLhs( Catch::toString( value ) ) - .setResultType( value ) - .endExpression(); - } - - // Only simple binary expressions are allowed on the LHS. - // If more complex compositions are required then place the sub expression in parentheses - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); - -private: - template - ResultBuilder& captureExpression( RhsT const& rhs ) { - return m_rb - .setResultType( Internal::compare( m_lhs, rhs ) ) - .setLhs( Catch::toString( m_lhs ) ) - .setRhs( Catch::toString( rhs ) ) - .setOp( Internal::OperatorTraits::getName() ); - } - -private: - ResultBuilder& m_rb; - T m_lhs; -}; - -} // end namespace Catch - - -namespace Catch { - - template - inline ExpressionLhs ResultBuilder::operator->* ( T const& operand ) { - return ExpressionLhs( *this, operand ); - } - - inline ExpressionLhs ResultBuilder::operator->* ( bool value ) { - return ExpressionLhs( *this, value ); - } - -} // namespace Catch - -// #included from: catch_message.h -#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED - -#include - -namespace Catch { - - struct MessageInfo { - MessageInfo( std::string const& _macroName, - SourceLineInfo const& _lineInfo, - ResultWas::OfType _type ); - - std::string macroName; - SourceLineInfo lineInfo; - ResultWas::OfType type; - std::string message; - unsigned int sequence; - - bool operator == ( MessageInfo const& other ) const { - return sequence == other.sequence; - } - bool operator < ( MessageInfo const& other ) const { - return sequence < other.sequence; - } - private: - static unsigned int globalCount; - }; - - struct MessageBuilder { - MessageBuilder( std::string const& macroName, - SourceLineInfo const& lineInfo, - ResultWas::OfType type ) - : m_info( macroName, lineInfo, type ) - {} - - template - MessageBuilder& operator << ( T const& value ) { - m_stream << value; - return *this; - } - - MessageInfo m_info; - std::ostringstream m_stream; - }; - - class ScopedMessage { - public: - ScopedMessage( MessageBuilder const& builder ); - ScopedMessage( ScopedMessage const& other ); - ~ScopedMessage(); - - MessageInfo m_info; - }; - -} // end namespace Catch - -// #included from: catch_interfaces_capture.h -#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED - -#include - -namespace Catch { - - class TestCase; - class AssertionResult; - struct AssertionInfo; - struct SectionInfo; - struct MessageInfo; - class ScopedMessageBuilder; - struct Counts; - - struct IResultCapture { - - virtual ~IResultCapture(); - - virtual void assertionEnded( AssertionResult const& result ) = 0; - virtual bool sectionStarted( SectionInfo const& sectionInfo, - Counts& assertions ) = 0; - virtual void sectionEnded( SectionInfo const& name, Counts const& assertions, double _durationInSeconds ) = 0; - virtual void pushScopedMessage( MessageInfo const& message ) = 0; - virtual void popScopedMessage( MessageInfo const& message ) = 0; - - virtual std::string getCurrentTestName() const = 0; - virtual const AssertionResult* getLastResult() const = 0; - - virtual void handleFatalErrorCondition( std::string const& message ) = 0; - }; - - IResultCapture& getResultCapture(); -} - -// #included from: catch_debugger.h -#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED - -// #included from: catch_platform.h -#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED - -#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) -#define CATCH_PLATFORM_MAC -#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) -#define CATCH_PLATFORM_IPHONE -#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) -#define CATCH_PLATFORM_WINDOWS -#endif - -#include - -namespace Catch{ - - bool isDebuggerActive(); - void writeToDebugConsole( std::string const& text ); -} - -#ifdef CATCH_PLATFORM_MAC - - // The following code snippet based on: - // http://cocoawithlove.com/2008/03/break-into-debugger.html - #ifdef DEBUG - #if defined(__ppc64__) || defined(__ppc__) - #define CATCH_BREAK_INTO_DEBUGGER() \ - if( Catch::isDebuggerActive() ) { \ - __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ - : : : "memory","r0","r3","r4" ); \ - } - #else - #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );} - #endif - #endif - -#elif defined(_MSC_VER) - #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); } -#elif defined(__MINGW32__) - extern "C" __declspec(dllimport) void __stdcall DebugBreak(); - #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); } -#endif - -#ifndef CATCH_BREAK_INTO_DEBUGGER -#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); -#endif - -// #included from: catch_interfaces_runner.h -#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED - -namespace Catch { - class TestCase; - - struct IRunner { - virtual ~IRunner(); - virtual bool aborting() const = 0; - }; -} - -/////////////////////////////////////////////////////////////////////////////// -// In the event of a failure works out if the debugger needs to be invoked -// and/or an exception thrown and takes appropriate action. -// This needs to be done as a macro so the debugger will stop in the user -// source code rather than in Catch library code -#define INTERNAL_CATCH_REACT( resultBuilder ) \ - if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ - resultBuilder.react(); - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \ - do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ - try { \ - ( __catchResult->*expr ).endExpression(); \ - } \ - catch( ... ) { \ - __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ - } \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::isTrue( false && (expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ - INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ - if( Catch::getResultCapture().getLastResult()->succeeded() ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \ - INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ - if( !Catch::getResultCapture().getLastResult()->succeeded() ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \ - do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ - try { \ - expr; \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ - } \ - catch( ... ) { \ - __catchResult.useActiveException( resultDisposition ); \ - } \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::alwaysFalse() ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS( expr, resultDisposition, macroName ) \ - do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ - if( __catchResult.allowThrows() ) \ - try { \ - expr; \ - __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ - } \ - catch( ... ) { \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ - } \ - else \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::alwaysFalse() ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \ - do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ - if( __catchResult.allowThrows() ) \ - try { \ - expr; \ - __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ - } \ - catch( exceptionType ) { \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ - } \ - catch( ... ) { \ - __catchResult.useActiveException( resultDisposition ); \ - } \ - else \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::alwaysFalse() ) - -/////////////////////////////////////////////////////////////////////////////// -#ifdef CATCH_CONFIG_VARIADIC_MACROS - #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \ - do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ - __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ - __catchResult.captureResult( messageType ); \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::alwaysFalse() ) -#else - #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \ - do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ - __catchResult << log + ::Catch::StreamEndStop(); \ - __catchResult.captureResult( messageType ); \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::alwaysFalse() ) -#endif - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_INFO( log, macroName ) \ - Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \ - do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \ - try { \ - std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \ - __catchResult \ - .setLhs( Catch::toString( arg ) ) \ - .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ - .setOp( "matches" ) \ - .setResultType( ::Catch::Matchers::matcher.match( arg ) ); \ - __catchResult.captureExpression(); \ - } catch( ... ) { \ - __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ - } \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::alwaysFalse() ) - -// #included from: internal/catch_section.h -#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED - -// #included from: catch_section_info.h -#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED - -namespace Catch { - - struct SectionInfo { - SectionInfo - ( SourceLineInfo const& _lineInfo, - std::string const& _name, - std::string const& _description = std::string() ); - - std::string name; - std::string description; - SourceLineInfo lineInfo; - }; - -} // end namespace Catch - -// #included from: catch_totals.hpp -#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED - -#include - -namespace Catch { - - struct Counts { - Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} - - Counts operator - ( Counts const& other ) const { - Counts diff; - diff.passed = passed - other.passed; - diff.failed = failed - other.failed; - diff.failedButOk = failedButOk - other.failedButOk; - return diff; - } - Counts& operator += ( Counts const& other ) { - passed += other.passed; - failed += other.failed; - failedButOk += other.failedButOk; - return *this; - } - - std::size_t total() const { - return passed + failed + failedButOk; - } - bool allPassed() const { - return failed == 0 && failedButOk == 0; - } - bool allOk() const { - return failed == 0; - } - - std::size_t passed; - std::size_t failed; - std::size_t failedButOk; - }; - - struct Totals { - - Totals operator - ( Totals const& other ) const { - Totals diff; - diff.assertions = assertions - other.assertions; - diff.testCases = testCases - other.testCases; - return diff; - } - - Totals delta( Totals const& prevTotals ) const { - Totals diff = *this - prevTotals; - if( diff.assertions.failed > 0 ) - ++diff.testCases.failed; - else if( diff.assertions.failedButOk > 0 ) - ++diff.testCases.failedButOk; - else - ++diff.testCases.passed; - return diff; - } - - Totals& operator += ( Totals const& other ) { - assertions += other.assertions; - testCases += other.testCases; - return *this; - } - - Counts assertions; - Counts testCases; - }; -} - -// #included from: catch_timer.h -#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED - -#ifdef CATCH_PLATFORM_WINDOWS -typedef unsigned long long uint64_t; -#else -#include -#endif - -namespace Catch { - - class Timer { - public: - Timer() : m_ticks( 0 ) {} - void start(); - unsigned int getElapsedMicroseconds() const; - unsigned int getElapsedMilliseconds() const; - double getElapsedSeconds() const; - - private: - uint64_t m_ticks; - }; - -} // namespace Catch - -#include - -namespace Catch { - - class Section : NonCopyable { - public: - Section( SectionInfo const& info ); - ~Section(); - - // This indicates whether the section should be executed or not - operator bool() const; - - private: - SectionInfo m_info; - - std::string m_name; - Counts m_assertions; - bool m_sectionIncluded; - Timer m_timer; - }; - -} // end namespace Catch - -#ifdef CATCH_CONFIG_VARIADIC_MACROS - #define INTERNAL_CATCH_SECTION( ... ) \ - if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) -#else - #define INTERNAL_CATCH_SECTION( name, desc ) \ - if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) -#endif - -// #included from: internal/catch_generators.hpp -#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED - -#include -#include -#include -#include - -namespace Catch { - -template -struct IGenerator { - virtual ~IGenerator() {} - virtual T getValue( std::size_t index ) const = 0; - virtual std::size_t size () const = 0; -}; - -template -class BetweenGenerator : public IGenerator { -public: - BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} - - virtual T getValue( std::size_t index ) const { - return m_from+static_cast( index ); - } - - virtual std::size_t size() const { - return static_cast( 1+m_to-m_from ); - } - -private: - - T m_from; - T m_to; -}; - -template -class ValuesGenerator : public IGenerator { -public: - ValuesGenerator(){} - - void add( T value ) { - m_values.push_back( value ); - } - - virtual T getValue( std::size_t index ) const { - return m_values[index]; - } - - virtual std::size_t size() const { - return m_values.size(); - } - -private: - std::vector m_values; -}; - -template -class CompositeGenerator { -public: - CompositeGenerator() : m_totalSize( 0 ) {} - - // *** Move semantics, similar to auto_ptr *** - CompositeGenerator( CompositeGenerator& other ) - : m_fileInfo( other.m_fileInfo ), - m_totalSize( 0 ) - { - move( other ); - } - - CompositeGenerator& setFileInfo( const char* fileInfo ) { - m_fileInfo = fileInfo; - return *this; - } - - ~CompositeGenerator() { - deleteAll( m_composed ); - } - - operator T () const { - size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); - - typename std::vector*>::const_iterator it = m_composed.begin(); - typename std::vector*>::const_iterator itEnd = m_composed.end(); - for( size_t index = 0; it != itEnd; ++it ) - { - const IGenerator* generator = *it; - if( overallIndex >= index && overallIndex < index + generator->size() ) - { - return generator->getValue( overallIndex-index ); - } - index += generator->size(); - } - CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); - return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so - } - - void add( const IGenerator* generator ) { - m_totalSize += generator->size(); - m_composed.push_back( generator ); - } - - CompositeGenerator& then( CompositeGenerator& other ) { - move( other ); - return *this; - } - - CompositeGenerator& then( T value ) { - ValuesGenerator* valuesGen = new ValuesGenerator(); - valuesGen->add( value ); - add( valuesGen ); - return *this; - } - -private: - - void move( CompositeGenerator& other ) { - std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) ); - m_totalSize += other.m_totalSize; - other.m_composed.clear(); - } - - std::vector*> m_composed; - std::string m_fileInfo; - size_t m_totalSize; -}; - -namespace Generators -{ - template - CompositeGenerator between( T from, T to ) { - CompositeGenerator generators; - generators.add( new BetweenGenerator( from, to ) ); - return generators; - } - - template - CompositeGenerator values( T val1, T val2 ) { - CompositeGenerator generators; - ValuesGenerator* valuesGen = new ValuesGenerator(); - valuesGen->add( val1 ); - valuesGen->add( val2 ); - generators.add( valuesGen ); - return generators; - } - - template - CompositeGenerator values( T val1, T val2, T val3 ){ - CompositeGenerator generators; - ValuesGenerator* valuesGen = new ValuesGenerator(); - valuesGen->add( val1 ); - valuesGen->add( val2 ); - valuesGen->add( val3 ); - generators.add( valuesGen ); - return generators; - } - - template - CompositeGenerator values( T val1, T val2, T val3, T val4 ) { - CompositeGenerator generators; - ValuesGenerator* valuesGen = new ValuesGenerator(); - valuesGen->add( val1 ); - valuesGen->add( val2 ); - valuesGen->add( val3 ); - valuesGen->add( val4 ); - generators.add( valuesGen ); - return generators; - } - -} // end namespace Generators - -using namespace Generators; - -} // end namespace Catch - -#define INTERNAL_CATCH_LINESTR2( line ) #line -#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) - -#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) - -// #included from: internal/catch_interfaces_exception.h -#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED - -#include -// #included from: catch_interfaces_registry_hub.h -#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED - -#include - -namespace Catch { - - class TestCase; - struct ITestCaseRegistry; - struct IExceptionTranslatorRegistry; - struct IExceptionTranslator; - struct IReporterRegistry; - struct IReporterFactory; - - struct IRegistryHub { - virtual ~IRegistryHub(); - - virtual IReporterRegistry const& getReporterRegistry() const = 0; - virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; - virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; - }; - - struct IMutableRegistryHub { - virtual ~IMutableRegistryHub(); - virtual void registerReporter( std::string const& name, IReporterFactory* factory ) = 0; - virtual void registerTest( TestCase const& testInfo ) = 0; - virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; - }; - - IRegistryHub& getRegistryHub(); - IMutableRegistryHub& getMutableRegistryHub(); - void cleanUp(); - std::string translateActiveException(); - -} - - -namespace Catch { - - typedef std::string(*exceptionTranslateFunction)(); - - struct IExceptionTranslator { - virtual ~IExceptionTranslator(); - virtual std::string translate() const = 0; - }; - - struct IExceptionTranslatorRegistry { - virtual ~IExceptionTranslatorRegistry(); - - virtual std::string translateActiveException() const = 0; - }; - - class ExceptionTranslatorRegistrar { - template - class ExceptionTranslator : public IExceptionTranslator { - public: - - ExceptionTranslator( std::string(*translateFunction)( T& ) ) - : m_translateFunction( translateFunction ) - {} - - virtual std::string translate() const { - try { - throw; - } - catch( T& ex ) { - return m_translateFunction( ex ); - } - } - - protected: - std::string(*m_translateFunction)( T& ); - }; - - public: - template - ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { - getMutableRegistryHub().registerTranslator - ( new ExceptionTranslator( translateFunction ) ); - } - }; -} - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \ - static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \ - namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\ - static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ) - -// #included from: internal/catch_approx.hpp -#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED - -#include -#include - -namespace Catch { -namespace Detail { - - class Approx { - public: - explicit Approx ( double value ) - : m_epsilon( std::numeric_limits::epsilon()*100 ), - m_scale( 1.0 ), - m_value( value ) - {} - - Approx( Approx const& other ) - : m_epsilon( other.m_epsilon ), - m_scale( other.m_scale ), - m_value( other.m_value ) - {} - - static Approx custom() { - return Approx( 0 ); - } - - Approx operator()( double value ) { - Approx approx( value ); - approx.epsilon( m_epsilon ); - approx.scale( m_scale ); - return approx; - } - - friend bool operator == ( double lhs, Approx const& rhs ) { - // Thanks to Richard Harris for his help refining this formula - return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) ); - } - - friend bool operator == ( Approx const& lhs, double rhs ) { - return operator==( rhs, lhs ); - } - - friend bool operator != ( double lhs, Approx const& rhs ) { - return !operator==( lhs, rhs ); - } - - friend bool operator != ( Approx const& lhs, double rhs ) { - return !operator==( rhs, lhs ); - } - - Approx& epsilon( double newEpsilon ) { - m_epsilon = newEpsilon; - return *this; - } - - Approx& scale( double newScale ) { - m_scale = newScale; - return *this; - } - - std::string toString() const { - std::ostringstream oss; - oss << "Approx( " << Catch::toString( m_value ) << " )"; - return oss.str(); - } - - private: - double m_epsilon; - double m_scale; - double m_value; - }; -} - -template<> -inline std::string toString( Detail::Approx const& value ) { - return value.toString(); -} - -} // end namespace Catch - -// #included from: internal/catch_matchers.hpp -#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED - -namespace Catch { -namespace Matchers { - namespace Impl { - - template - struct Matcher : SharedImpl - { - typedef ExpressionT ExpressionType; - - virtual ~Matcher() {} - virtual Ptr clone() const = 0; - virtual bool match( ExpressionT const& expr ) const = 0; - virtual std::string toString() const = 0; - }; - - template - struct MatcherImpl : Matcher { - - virtual Ptr > clone() const { - return Ptr >( new DerivedT( static_cast( *this ) ) ); - } - }; - - namespace Generic { - - template - class AllOf : public MatcherImpl, ExpressionT> { - public: - - AllOf() {} - AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} - - AllOf& add( Matcher const& matcher ) { - m_matchers.push_back( matcher.clone() ); - return *this; - } - virtual bool match( ExpressionT const& expr ) const - { - for( std::size_t i = 0; i < m_matchers.size(); ++i ) - if( !m_matchers[i]->match( expr ) ) - return false; - return true; - } - virtual std::string toString() const { - std::ostringstream oss; - oss << "( "; - for( std::size_t i = 0; i < m_matchers.size(); ++i ) { - if( i != 0 ) - oss << " and "; - oss << m_matchers[i]->toString(); - } - oss << " )"; - return oss.str(); - } - - private: - std::vector > > m_matchers; - }; - - template - class AnyOf : public MatcherImpl, ExpressionT> { - public: - - AnyOf() {} - AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} - - AnyOf& add( Matcher const& matcher ) { - m_matchers.push_back( matcher.clone() ); - return *this; - } - virtual bool match( ExpressionT const& expr ) const - { - for( std::size_t i = 0; i < m_matchers.size(); ++i ) - if( m_matchers[i]->match( expr ) ) - return true; - return false; - } - virtual std::string toString() const { - std::ostringstream oss; - oss << "( "; - for( std::size_t i = 0; i < m_matchers.size(); ++i ) { - if( i != 0 ) - oss << " or "; - oss << m_matchers[i]->toString(); - } - oss << " )"; - return oss.str(); - } - - private: - std::vector > > m_matchers; - }; - - } - - namespace StdString { - - inline std::string makeString( std::string const& str ) { return str; } - inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } - - struct Equals : MatcherImpl { - Equals( std::string const& str ) : m_str( str ){} - Equals( Equals const& other ) : m_str( other.m_str ){} - - virtual ~Equals(); - - virtual bool match( std::string const& expr ) const { - return m_str == expr; - } - virtual std::string toString() const { - return "equals: \"" + m_str + "\""; - } - - std::string m_str; - }; - - struct Contains : MatcherImpl { - Contains( std::string const& substr ) : m_substr( substr ){} - Contains( Contains const& other ) : m_substr( other.m_substr ){} - - virtual ~Contains(); - - virtual bool match( std::string const& expr ) const { - return expr.find( m_substr ) != std::string::npos; - } - virtual std::string toString() const { - return "contains: \"" + m_substr + "\""; - } - - std::string m_substr; - }; - - struct StartsWith : MatcherImpl { - StartsWith( std::string const& substr ) : m_substr( substr ){} - StartsWith( StartsWith const& other ) : m_substr( other.m_substr ){} - - virtual ~StartsWith(); - - virtual bool match( std::string const& expr ) const { - return expr.find( m_substr ) == 0; - } - virtual std::string toString() const { - return "starts with: \"" + m_substr + "\""; - } - - std::string m_substr; - }; - - struct EndsWith : MatcherImpl { - EndsWith( std::string const& substr ) : m_substr( substr ){} - EndsWith( EndsWith const& other ) : m_substr( other.m_substr ){} - - virtual ~EndsWith(); - - virtual bool match( std::string const& expr ) const { - return expr.find( m_substr ) == expr.size() - m_substr.size(); - } - virtual std::string toString() const { - return "ends with: \"" + m_substr + "\""; - } - - std::string m_substr; - }; - } // namespace StdString - } // namespace Impl - - // The following functions create the actual matcher objects. - // This allows the types to be inferred - template - inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, - Impl::Matcher const& m2 ) { - return Impl::Generic::AllOf().add( m1 ).add( m2 ); - } - template - inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, - Impl::Matcher const& m2, - Impl::Matcher const& m3 ) { - return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); - } - template - inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, - Impl::Matcher const& m2 ) { - return Impl::Generic::AnyOf().add( m1 ).add( m2 ); - } - template - inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, - Impl::Matcher const& m2, - Impl::Matcher const& m3 ) { - return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); - } - - inline Impl::StdString::Equals Equals( std::string const& str ) { - return Impl::StdString::Equals( str ); - } - inline Impl::StdString::Equals Equals( const char* str ) { - return Impl::StdString::Equals( Impl::StdString::makeString( str ) ); - } - inline Impl::StdString::Contains Contains( std::string const& substr ) { - return Impl::StdString::Contains( substr ); - } - inline Impl::StdString::Contains Contains( const char* substr ) { - return Impl::StdString::Contains( Impl::StdString::makeString( substr ) ); - } - inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { - return Impl::StdString::StartsWith( substr ); - } - inline Impl::StdString::StartsWith StartsWith( const char* substr ) { - return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); - } - inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { - return Impl::StdString::EndsWith( substr ); - } - inline Impl::StdString::EndsWith EndsWith( const char* substr ) { - return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); - } - -} // namespace Matchers - -using namespace Matchers; - -} // namespace Catch - -// #included from: internal/catch_interfaces_tag_alias_registry.h -#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED - -// #included from: catch_tag_alias.h -#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED - -#include - -namespace Catch { - - struct TagAlias { - TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} - - std::string tag; - SourceLineInfo lineInfo; - }; - - struct RegistrarForTagAliases { - RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); - }; - -} // end namespace Catch - -#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } -// #included from: catch_option.hpp -#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED - -namespace Catch { - - // An optional type - template - class Option { - public: - Option() : nullableValue( NULL ) {} - Option( T const& _value ) - : nullableValue( new( storage ) T( _value ) ) - {} - Option( Option const& _other ) - : nullableValue( _other ? new( storage ) T( *_other ) : NULL ) - {} - - ~Option() { - reset(); - } - - Option& operator= ( Option const& _other ) { - if( &_other != this ) { - reset(); - if( _other ) - nullableValue = new( storage ) T( *_other ); - } - return *this; - } - Option& operator = ( T const& _value ) { - reset(); - nullableValue = new( storage ) T( _value ); - return *this; - } - - void reset() { - if( nullableValue ) - nullableValue->~T(); - nullableValue = NULL; - } - - T& operator*() { return *nullableValue; } - T const& operator*() const { return *nullableValue; } - T* operator->() { return nullableValue; } - const T* operator->() const { return nullableValue; } - - T valueOr( T const& defaultValue ) const { - return nullableValue ? *nullableValue : defaultValue; - } - - bool some() const { return nullableValue != NULL; } - bool none() const { return nullableValue == NULL; } - - bool operator !() const { return nullableValue == NULL; } - operator SafeBool::type() const { - return SafeBool::makeSafe( some() ); - } - - private: - T* nullableValue; - char storage[sizeof(T)]; - }; - -} // end namespace Catch - -namespace Catch { - - struct ITagAliasRegistry { - virtual ~ITagAliasRegistry(); - virtual Option find( std::string const& alias ) const = 0; - virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; - - static ITagAliasRegistry const& get(); - }; - -} // end namespace Catch - -// These files are included here so the single_include script doesn't put them -// in the conditionally compiled sections -// #included from: internal/catch_test_case_info.h -#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED - -#include -#include - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#endif - -namespace Catch { - - struct ITestCase; - - struct TestCaseInfo { - enum SpecialProperties{ - None = 0, - IsHidden = 1 << 1, - ShouldFail = 1 << 2, - MayFail = 1 << 3, - Throws = 1 << 4 - }; - - TestCaseInfo( std::string const& _name, - std::string const& _className, - std::string const& _description, - std::set const& _tags, - SourceLineInfo const& _lineInfo ); - - TestCaseInfo( TestCaseInfo const& other ); - - bool isHidden() const; - bool throws() const; - bool okToFail() const; - bool expectedToFail() const; - - std::string name; - std::string className; - std::string description; - std::set tags; - std::set lcaseTags; - std::string tagsAsString; - SourceLineInfo lineInfo; - SpecialProperties properties; - }; - - class TestCase : public TestCaseInfo { - public: - - TestCase( ITestCase* testCase, TestCaseInfo const& info ); - TestCase( TestCase const& other ); - - TestCase withName( std::string const& _newName ) const; - - void invoke() const; - - TestCaseInfo const& getTestCaseInfo() const; - - void swap( TestCase& other ); - bool operator == ( TestCase const& other ) const; - bool operator < ( TestCase const& other ) const; - TestCase& operator = ( TestCase const& other ); - - private: - Ptr test; - }; - - TestCase makeTestCase( ITestCase* testCase, - std::string const& className, - std::string const& name, - std::string const& description, - SourceLineInfo const& lineInfo ); -} - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - - -#ifdef __OBJC__ -// #included from: internal/catch_objc.hpp -#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED - -#import - -#include - -// NB. Any general catch headers included here must be included -// in catch.hpp first to make sure they are included by the single -// header for non obj-usage - -/////////////////////////////////////////////////////////////////////////////// -// This protocol is really only here for (self) documenting purposes, since -// all its methods are optional. -@protocol OcFixture - -@optional - --(void) setUp; --(void) tearDown; - -@end - -namespace Catch { - - class OcMethod : public SharedImpl { - - public: - OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} - - virtual void invoke() const { - id obj = [[m_cls alloc] init]; - - performOptionalSelector( obj, @selector(setUp) ); - performOptionalSelector( obj, m_sel ); - performOptionalSelector( obj, @selector(tearDown) ); - - arcSafeRelease( obj ); - } - private: - virtual ~OcMethod() {} - - Class m_cls; - SEL m_sel; - }; - - namespace Detail{ - - inline std::string getAnnotation( Class cls, - std::string const& annotationName, - std::string const& testCaseName ) { - NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; - SEL sel = NSSelectorFromString( selStr ); - arcSafeRelease( selStr ); - id value = performOptionalSelector( cls, sel ); - if( value ) - return [(NSString*)value UTF8String]; - return ""; - } - } - - inline size_t registerTestMethods() { - size_t noTestMethods = 0; - int noClasses = objc_getClassList( NULL, 0 ); - - Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); - objc_getClassList( classes, noClasses ); - - for( int c = 0; c < noClasses; c++ ) { - Class cls = classes[c]; - { - u_int count; - Method* methods = class_copyMethodList( cls, &count ); - for( u_int m = 0; m < count ; m++ ) { - SEL selector = method_getName(methods[m]); - std::string methodName = sel_getName(selector); - if( startsWith( methodName, "Catch_TestCase_" ) ) { - std::string testCaseName = methodName.substr( 15 ); - std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); - std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); - const char* className = class_getName( cls ); - - getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); - noTestMethods++; - } - } - free(methods); - } - } - return noTestMethods; - } - - namespace Matchers { - namespace Impl { - namespace NSStringMatchers { - - template - struct StringHolder : MatcherImpl{ - StringHolder( NSString* substr ) : m_substr( [substr copy] ){} - StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} - StringHolder() { - arcSafeRelease( m_substr ); - } - - NSString* m_substr; - }; - - struct Equals : StringHolder { - Equals( NSString* substr ) : StringHolder( substr ){} - - virtual bool match( ExpressionType const& str ) const { - return (str != nil || m_substr == nil ) && - [str isEqualToString:m_substr]; - } - - virtual std::string toString() const { - return "equals string: " + Catch::toString( m_substr ); - } - }; - - struct Contains : StringHolder { - Contains( NSString* substr ) : StringHolder( substr ){} - - virtual bool match( ExpressionType const& str ) const { - return (str != nil || m_substr == nil ) && - [str rangeOfString:m_substr].location != NSNotFound; - } - - virtual std::string toString() const { - return "contains string: " + Catch::toString( m_substr ); - } - }; - - struct StartsWith : StringHolder { - StartsWith( NSString* substr ) : StringHolder( substr ){} - - virtual bool match( ExpressionType const& str ) const { - return (str != nil || m_substr == nil ) && - [str rangeOfString:m_substr].location == 0; - } - - virtual std::string toString() const { - return "starts with: " + Catch::toString( m_substr ); - } - }; - struct EndsWith : StringHolder { - EndsWith( NSString* substr ) : StringHolder( substr ){} - - virtual bool match( ExpressionType const& str ) const { - return (str != nil || m_substr == nil ) && - [str rangeOfString:m_substr].location == [str length] - [m_substr length]; - } - - virtual std::string toString() const { - return "ends with: " + Catch::toString( m_substr ); - } - }; - - } // namespace NSStringMatchers - } // namespace Impl - - inline Impl::NSStringMatchers::Equals - Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } - - inline Impl::NSStringMatchers::Contains - Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } - - inline Impl::NSStringMatchers::StartsWith - StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } - - inline Impl::NSStringMatchers::EndsWith - EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } - - } // namespace Matchers - - using namespace Matchers; - -} // namespace Catch - -/////////////////////////////////////////////////////////////////////////////// -#define OC_TEST_CASE( name, desc )\ -+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ -{\ -return @ name; \ -}\ -+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ -{ \ -return @ desc; \ -} \ --(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) - -#endif - -#ifdef CATCH_IMPL -// #included from: internal/catch_impl.hpp -#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED - -// Collect all the implementation files together here -// These are the equivalent of what would usually be cpp files - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wweak-vtables" -#endif - -// #included from: catch_runner.hpp -#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED - -// #included from: internal/catch_commandline.hpp -#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED - -// #included from: catch_config.hpp -#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED - -// #included from: catch_test_spec_parser.hpp -#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#endif - -// #included from: catch_test_spec.hpp -#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#endif - -#include -#include - -namespace Catch { - - class TestSpec { - struct Pattern : SharedImpl<> { - virtual ~Pattern(); - virtual bool matches( TestCaseInfo const& testCase ) const = 0; - }; - class NamePattern : public Pattern { - enum WildcardPosition { - NoWildcard = 0, - WildcardAtStart = 1, - WildcardAtEnd = 2, - WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd - }; - - public: - NamePattern( std::string const& name ) : m_name( toLower( name ) ), m_wildcard( NoWildcard ) { - if( startsWith( m_name, "*" ) ) { - m_name = m_name.substr( 1 ); - m_wildcard = WildcardAtStart; - } - if( endsWith( m_name, "*" ) ) { - m_name = m_name.substr( 0, m_name.size()-1 ); - m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); - } - } - virtual ~NamePattern(); - virtual bool matches( TestCaseInfo const& testCase ) const { - switch( m_wildcard ) { - case NoWildcard: - return m_name == toLower( testCase.name ); - case WildcardAtStart: - return endsWith( toLower( testCase.name ), m_name ); - case WildcardAtEnd: - return startsWith( toLower( testCase.name ), m_name ); - case WildcardAtBothEnds: - return contains( toLower( testCase.name ), m_name ); - } - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunreachable-code" -#endif - throw std::logic_error( "Unknown enum" ); -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - } - private: - std::string m_name; - WildcardPosition m_wildcard; - }; - class TagPattern : public Pattern { - public: - TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} - virtual ~TagPattern(); - virtual bool matches( TestCaseInfo const& testCase ) const { - return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); - } - private: - std::string m_tag; - }; - class ExcludedPattern : public Pattern { - public: - ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} - virtual ~ExcludedPattern(); - virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } - private: - Ptr m_underlyingPattern; - }; - - struct Filter { - std::vector > m_patterns; - - bool matches( TestCaseInfo const& testCase ) const { - // All patterns in a filter must match for the filter to be a match - for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) - if( !(*it)->matches( testCase ) ) - return false; - return true; - } - }; - - public: - bool hasFilters() const { - return !m_filters.empty(); - } - bool matches( TestCaseInfo const& testCase ) const { - // A TestSpec matches if any filter matches - for( std::vector::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) - if( it->matches( testCase ) ) - return true; - return false; - } - - private: - std::vector m_filters; - - friend class TestSpecParser; - }; -} - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -namespace Catch { - - class TestSpecParser { - enum Mode{ None, Name, QuotedName, Tag }; - Mode m_mode; - bool m_exclusion; - std::size_t m_start, m_pos; - std::string m_arg; - TestSpec::Filter m_currentFilter; - TestSpec m_testSpec; - ITagAliasRegistry const* m_tagAliases; - - public: - TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} - - TestSpecParser& parse( std::string const& arg ) { - m_mode = None; - m_exclusion = false; - m_start = std::string::npos; - m_arg = m_tagAliases->expandAliases( arg ); - for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) - visitChar( m_arg[m_pos] ); - if( m_mode == Name ) - addPattern(); - return *this; - } - TestSpec testSpec() { - addFilter(); - return m_testSpec; - } - private: - void visitChar( char c ) { - if( m_mode == None ) { - switch( c ) { - case ' ': return; - case '~': m_exclusion = true; return; - case '[': return startNewMode( Tag, ++m_pos ); - case '"': return startNewMode( QuotedName, ++m_pos ); - default: startNewMode( Name, m_pos ); break; - } - } - if( m_mode == Name ) { - if( c == ',' ) { - addPattern(); - addFilter(); - } - else if( c == '[' ) { - if( subString() == "exclude:" ) - m_exclusion = true; - else - addPattern(); - startNewMode( Tag, ++m_pos ); - } - } - else if( m_mode == QuotedName && c == '"' ) - addPattern(); - else if( m_mode == Tag && c == ']' ) - addPattern(); - } - void startNewMode( Mode mode, std::size_t start ) { - m_mode = mode; - m_start = start; - } - std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } - template - void addPattern() { - std::string token = subString(); - if( startsWith( token, "exclude:" ) ) { - m_exclusion = true; - token = token.substr( 8 ); - } - if( !token.empty() ) { - Ptr pattern = new T( token ); - if( m_exclusion ) - pattern = new TestSpec::ExcludedPattern( pattern ); - m_currentFilter.m_patterns.push_back( pattern ); - } - m_exclusion = false; - m_mode = None; - } - void addFilter() { - if( !m_currentFilter.m_patterns.empty() ) { - m_testSpec.m_filters.push_back( m_currentFilter ); - m_currentFilter = TestSpec::Filter(); - } - } - }; - inline TestSpec parseTestSpec( std::string const& arg ) { - return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); - } - -} // namespace Catch - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -// #included from: catch_interfaces_config.h -#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED - -#include -#include -#include - -namespace Catch { - - struct Verbosity { enum Level { - NoOutput = 0, - Quiet, - Normal - }; }; - - struct WarnAbout { enum What { - Nothing = 0x00, - NoAssertions = 0x01 - }; }; - - struct ShowDurations { enum OrNot { - DefaultForReporter, - Always, - Never - }; }; - struct RunTests { enum InWhatOrder { - InDeclarationOrder, - InLexicographicalOrder, - InRandomOrder - }; }; - - class TestSpec; - - struct IConfig : IShared { - - virtual ~IConfig(); - - virtual bool allowThrows() const = 0; - virtual std::ostream& stream() const = 0; - virtual std::string name() const = 0; - virtual bool includeSuccessfulResults() const = 0; - virtual bool shouldDebugBreak() const = 0; - virtual bool warnAboutMissingAssertions() const = 0; - virtual int abortAfter() const = 0; - virtual bool showInvisibles() const = 0; - virtual ShowDurations::OrNot showDurations() const = 0; - virtual TestSpec const& testSpec() const = 0; - virtual RunTests::InWhatOrder runOrder() const = 0; - virtual unsigned int rngSeed() const = 0; - }; -} - -// #included from: catch_stream.h -#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED - -#include - -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wpadded" -#endif - -namespace Catch { - - class Stream { - public: - Stream(); - Stream( std::streambuf* _streamBuf, bool _isOwned ); - void release(); - - std::streambuf* streamBuf; - - private: - bool isOwned; - }; - - std::ostream& cout(); - std::ostream& cerr(); -} - -#include -#include -#include -#include -#include - -#ifndef CATCH_CONFIG_CONSOLE_WIDTH -#define CATCH_CONFIG_CONSOLE_WIDTH 80 -#endif - -namespace Catch { - - struct ConfigData { - - ConfigData() - : listTests( false ), - listTags( false ), - listReporters( false ), - listTestNamesOnly( false ), - showSuccessfulTests( false ), - shouldDebugBreak( false ), - noThrow( false ), - showHelp( false ), - showInvisibles( false ), - abortAfter( -1 ), - rngSeed( 0 ), - verbosity( Verbosity::Normal ), - warnings( WarnAbout::Nothing ), - showDurations( ShowDurations::DefaultForReporter ), - runOrder( RunTests::InDeclarationOrder ) - {} - - bool listTests; - bool listTags; - bool listReporters; - bool listTestNamesOnly; - - bool showSuccessfulTests; - bool shouldDebugBreak; - bool noThrow; - bool showHelp; - bool showInvisibles; - - int abortAfter; - unsigned int rngSeed; - - Verbosity::Level verbosity; - WarnAbout::What warnings; - ShowDurations::OrNot showDurations; - RunTests::InWhatOrder runOrder; - - std::string reporterName; - std::string outputFilename; - std::string name; - std::string processName; - - std::vector testsOrTags; - }; - - class Config : public SharedImpl { - private: - Config( Config const& other ); - Config& operator = ( Config const& other ); - virtual void dummy(); - public: - - Config() - : m_os( Catch::cout().rdbuf() ) - {} - - Config( ConfigData const& data ) - : m_data( data ), - m_os( Catch::cout().rdbuf() ) - { - if( !data.testsOrTags.empty() ) { - TestSpecParser parser( ITagAliasRegistry::get() ); - for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) - parser.parse( data.testsOrTags[i] ); - m_testSpec = parser.testSpec(); - } - } - - virtual ~Config() { - m_os.rdbuf( Catch::cout().rdbuf() ); - m_stream.release(); - } - - void setFilename( std::string const& filename ) { - m_data.outputFilename = filename; - } - - std::string const& getFilename() const { - return m_data.outputFilename ; - } - - bool listTests() const { return m_data.listTests; } - bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } - bool listTags() const { return m_data.listTags; } - bool listReporters() const { return m_data.listReporters; } - - std::string getProcessName() const { return m_data.processName; } - - bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } - - void setStreamBuf( std::streambuf* buf ) { - m_os.rdbuf( buf ? buf : Catch::cout().rdbuf() ); - } - - void useStream( std::string const& streamName ) { - Stream stream = createStream( streamName ); - setStreamBuf( stream.streamBuf ); - m_stream.release(); - m_stream = stream; - } - - std::string getReporterName() const { return m_data.reporterName; } - - int abortAfter() const { return m_data.abortAfter; } - - TestSpec const& testSpec() const { return m_testSpec; } - - bool showHelp() const { return m_data.showHelp; } - bool showInvisibles() const { return m_data.showInvisibles; } - - // IConfig interface - virtual bool allowThrows() const { return !m_data.noThrow; } - virtual std::ostream& stream() const { return m_os; } - virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } - virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } - virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } - virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; } - virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; } - virtual unsigned int rngSeed() const { return m_data.rngSeed; } - - private: - ConfigData m_data; - - Stream m_stream; - mutable std::ostream m_os; - TestSpec m_testSpec; - }; - -} // end namespace Catch - -// #included from: catch_clara.h -#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED - -// Use Catch's value for console width (store Clara's off to the side, if present) -#ifdef CLARA_CONFIG_CONSOLE_WIDTH -#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH -#undef CLARA_CONFIG_CONSOLE_WIDTH -#endif -#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH - -// Declare Clara inside the Catch namespace -#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { -// #included from: ../external/clara.h - -// Only use header guard if we are not using an outer namespace -#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) - -#ifndef STITCH_CLARA_OPEN_NAMESPACE -#define TWOBLUECUBES_CLARA_H_INCLUDED -#define STITCH_CLARA_OPEN_NAMESPACE -#define STITCH_CLARA_CLOSE_NAMESPACE -#else -#define STITCH_CLARA_CLOSE_NAMESPACE } -#endif - -#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE - -// ----------- #included from tbc_text_format.h ----------- - -// Only use header guard if we are not using an outer namespace -#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) -#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE -#define TBC_TEXT_FORMAT_H_INCLUDED -#endif - -#include -#include -#include - -// Use optional outer namespace -#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE -namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { -#endif - -namespace Tbc { - -#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH - const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; -#else - const unsigned int consoleWidth = 80; -#endif - - struct TextAttributes { - TextAttributes() - : initialIndent( std::string::npos ), - indent( 0 ), - width( consoleWidth-1 ), - tabChar( '\t' ) - {} - - TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } - TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } - TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } - TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } - - std::size_t initialIndent; // indent of first line, or npos - std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos - std::size_t width; // maximum width of text, including indent. Longer text will wrap - char tabChar; // If this char is seen the indent is changed to current pos - }; - - class Text { - public: - Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) - : attr( _attr ) - { - std::string wrappableChars = " [({.,/|\\-"; - std::size_t indent = _attr.initialIndent != std::string::npos - ? _attr.initialIndent - : _attr.indent; - std::string remainder = _str; - - while( !remainder.empty() ) { - if( lines.size() >= 1000 ) { - lines.push_back( "... message truncated due to excessive size" ); - return; - } - std::size_t tabPos = std::string::npos; - std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); - std::size_t pos = remainder.find_first_of( '\n' ); - if( pos <= width ) { - width = pos; - } - pos = remainder.find_last_of( _attr.tabChar, width ); - if( pos != std::string::npos ) { - tabPos = pos; - if( remainder[width] == '\n' ) - width--; - remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); - } - - if( width == remainder.size() ) { - spliceLine( indent, remainder, width ); - } - else if( remainder[width] == '\n' ) { - spliceLine( indent, remainder, width ); - if( width <= 1 || remainder.size() != 1 ) - remainder = remainder.substr( 1 ); - indent = _attr.indent; - } - else { - pos = remainder.find_last_of( wrappableChars, width ); - if( pos != std::string::npos && pos > 0 ) { - spliceLine( indent, remainder, pos ); - if( remainder[0] == ' ' ) - remainder = remainder.substr( 1 ); - } - else { - spliceLine( indent, remainder, width-1 ); - lines.back() += "-"; - } - if( lines.size() == 1 ) - indent = _attr.indent; - if( tabPos != std::string::npos ) - indent += tabPos; - } - } - } - - void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { - lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); - _remainder = _remainder.substr( _pos ); - } - - typedef std::vector::const_iterator const_iterator; - - const_iterator begin() const { return lines.begin(); } - const_iterator end() const { return lines.end(); } - std::string const& last() const { return lines.back(); } - std::size_t size() const { return lines.size(); } - std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } - std::string toString() const { - std::ostringstream oss; - oss << *this; - return oss.str(); - } - - inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { - for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); - it != itEnd; ++it ) { - if( it != _text.begin() ) - _stream << "\n"; - _stream << *it; - } - return _stream; - } - - private: - std::string str; - TextAttributes attr; - std::vector lines; - }; - -} // end namespace Tbc - -#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE -} // end outer namespace -#endif - -#endif // TBC_TEXT_FORMAT_H_INCLUDED - -// ----------- end of #include from tbc_text_format.h ----------- -// ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h - -#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE - -#include -#include -#include -#include - -// Use optional outer namespace -#ifdef STITCH_CLARA_OPEN_NAMESPACE -STITCH_CLARA_OPEN_NAMESPACE -#endif - -namespace Clara { - - struct UnpositionalTag {}; - - extern UnpositionalTag _; - -#ifdef CLARA_CONFIG_MAIN - UnpositionalTag _; -#endif - - namespace Detail { - -#ifdef CLARA_CONSOLE_WIDTH - const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; -#else - const unsigned int consoleWidth = 80; -#endif - - using namespace Tbc; - - inline bool startsWith( std::string const& str, std::string const& prefix ) { - return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; - } - - template struct RemoveConstRef{ typedef T type; }; - template struct RemoveConstRef{ typedef T type; }; - template struct RemoveConstRef{ typedef T type; }; - template struct RemoveConstRef{ typedef T type; }; - - template struct IsBool { static const bool value = false; }; - template<> struct IsBool { static const bool value = true; }; - - template - void convertInto( std::string const& _source, T& _dest ) { - std::stringstream ss; - ss << _source; - ss >> _dest; - if( ss.fail() ) - throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); - } - inline void convertInto( std::string const& _source, std::string& _dest ) { - _dest = _source; - } - inline void convertInto( std::string const& _source, bool& _dest ) { - std::string sourceLC = _source; - std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower ); - if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) - _dest = true; - else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) - _dest = false; - else - throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); - } - inline void convertInto( bool _source, bool& _dest ) { - _dest = _source; - } - template - inline void convertInto( bool, T& ) { - throw std::runtime_error( "Invalid conversion" ); - } - - template - struct IArgFunction { - virtual ~IArgFunction() {} -# ifdef CATCH_CPP11_OR_GREATER - IArgFunction() = default; - IArgFunction( IArgFunction const& ) = default; -# endif - virtual void set( ConfigT& config, std::string const& value ) const = 0; - virtual void setFlag( ConfigT& config ) const = 0; - virtual bool takesArg() const = 0; - virtual IArgFunction* clone() const = 0; - }; - - template - class BoundArgFunction { - public: - BoundArgFunction() : functionObj( NULL ) {} - BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} - BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : NULL ) {} - BoundArgFunction& operator = ( BoundArgFunction const& other ) { - IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : NULL; - delete functionObj; - functionObj = newFunctionObj; - return *this; - } - ~BoundArgFunction() { delete functionObj; } - - void set( ConfigT& config, std::string const& value ) const { - functionObj->set( config, value ); - } - void setFlag( ConfigT& config ) const { - functionObj->setFlag( config ); - } - bool takesArg() const { return functionObj->takesArg(); } - - bool isSet() const { - return functionObj != NULL; - } - private: - IArgFunction* functionObj; - }; - - template - struct NullBinder : IArgFunction{ - virtual void set( C&, std::string const& ) const {} - virtual void setFlag( C& ) const {} - virtual bool takesArg() const { return true; } - virtual IArgFunction* clone() const { return new NullBinder( *this ); } - }; - - template - struct BoundDataMember : IArgFunction{ - BoundDataMember( M C::* _member ) : member( _member ) {} - virtual void set( C& p, std::string const& stringValue ) const { - convertInto( stringValue, p.*member ); - } - virtual void setFlag( C& p ) const { - convertInto( true, p.*member ); - } - virtual bool takesArg() const { return !IsBool::value; } - virtual IArgFunction* clone() const { return new BoundDataMember( *this ); } - M C::* member; - }; - template - struct BoundUnaryMethod : IArgFunction{ - BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} - virtual void set( C& p, std::string const& stringValue ) const { - typename RemoveConstRef::type value; - convertInto( stringValue, value ); - (p.*member)( value ); - } - virtual void setFlag( C& p ) const { - typename RemoveConstRef::type value; - convertInto( true, value ); - (p.*member)( value ); - } - virtual bool takesArg() const { return !IsBool::value; } - virtual IArgFunction* clone() const { return new BoundUnaryMethod( *this ); } - void (C::*member)( M ); - }; - template - struct BoundNullaryMethod : IArgFunction{ - BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} - virtual void set( C& p, std::string const& stringValue ) const { - bool value; - convertInto( stringValue, value ); - if( value ) - (p.*member)(); - } - virtual void setFlag( C& p ) const { - (p.*member)(); - } - virtual bool takesArg() const { return false; } - virtual IArgFunction* clone() const { return new BoundNullaryMethod( *this ); } - void (C::*member)(); - }; - - template - struct BoundUnaryFunction : IArgFunction{ - BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} - virtual void set( C& obj, std::string const& stringValue ) const { - bool value; - convertInto( stringValue, value ); - if( value ) - function( obj ); - } - virtual void setFlag( C& p ) const { - function( p ); - } - virtual bool takesArg() const { return false; } - virtual IArgFunction* clone() const { return new BoundUnaryFunction( *this ); } - void (*function)( C& ); - }; - - template - struct BoundBinaryFunction : IArgFunction{ - BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} - virtual void set( C& obj, std::string const& stringValue ) const { - typename RemoveConstRef::type value; - convertInto( stringValue, value ); - function( obj, value ); - } - virtual void setFlag( C& obj ) const { - typename RemoveConstRef::type value; - convertInto( true, value ); - function( obj, value ); - } - virtual bool takesArg() const { return !IsBool::value; } - virtual IArgFunction* clone() const { return new BoundBinaryFunction( *this ); } - void (*function)( C&, T ); - }; - - } // namespace Detail - - struct Parser { - Parser() : separators( " \t=:" ) {} - - struct Token { - enum Type { Positional, ShortOpt, LongOpt }; - Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} - Type type; - std::string data; - }; - - void parseIntoTokens( int argc, char const * const * argv, std::vector& tokens ) const { - const std::string doubleDash = "--"; - for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) - parseIntoTokens( argv[i] , tokens); - } - void parseIntoTokens( std::string arg, std::vector& tokens ) const { - while( !arg.empty() ) { - Parser::Token token( Parser::Token::Positional, arg ); - arg = ""; - if( token.data[0] == '-' ) { - if( token.data.size() > 1 && token.data[1] == '-' ) { - token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); - } - else { - token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) ); - if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) { - arg = "-" + token.data.substr( 1 ); - token.data = token.data.substr( 0, 1 ); - } - } - } - if( token.type != Parser::Token::Positional ) { - std::size_t pos = token.data.find_first_of( separators ); - if( pos != std::string::npos ) { - arg = token.data.substr( pos+1 ); - token.data = token.data.substr( 0, pos ); - } - } - tokens.push_back( token ); - } - } - std::string separators; - }; - - template - struct CommonArgProperties { - CommonArgProperties() {} - CommonArgProperties( Detail::BoundArgFunction const& _boundField ) : boundField( _boundField ) {} - - Detail::BoundArgFunction boundField; - std::string description; - std::string detail; - std::string placeholder; // Only value if boundField takes an arg - - bool takesArg() const { - return !placeholder.empty(); - } - void validate() const { - if( !boundField.isSet() ) - throw std::logic_error( "option not bound" ); - } - }; - struct OptionArgProperties { - std::vector shortNames; - std::string longName; - - bool hasShortName( std::string const& shortName ) const { - return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); - } - bool hasLongName( std::string const& _longName ) const { - return _longName == longName; - } - }; - struct PositionalArgProperties { - PositionalArgProperties() : position( -1 ) {} - int position; // -1 means non-positional (floating) - - bool isFixedPositional() const { - return position != -1; - } - }; - - template - class CommandLine { - - struct Arg : CommonArgProperties, OptionArgProperties, PositionalArgProperties { - Arg() {} - Arg( Detail::BoundArgFunction const& _boundField ) : CommonArgProperties( _boundField ) {} - - using CommonArgProperties::placeholder; // !TBD - - std::string dbgName() const { - if( !longName.empty() ) - return "--" + longName; - if( !shortNames.empty() ) - return "-" + shortNames[0]; - return "positional args"; - } - std::string commands() const { - std::ostringstream oss; - bool first = true; - std::vector::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); - for(; it != itEnd; ++it ) { - if( first ) - first = false; - else - oss << ", "; - oss << "-" << *it; - } - if( !longName.empty() ) { - if( !first ) - oss << ", "; - oss << "--" << longName; - } - if( !placeholder.empty() ) - oss << " <" << placeholder << ">"; - return oss.str(); - } - }; - - // NOTE: std::auto_ptr is deprecated in c++11/c++0x -#if defined(__cplusplus) && __cplusplus > 199711L - typedef std::unique_ptr ArgAutoPtr; -#else - typedef std::auto_ptr ArgAutoPtr; -#endif - - friend void addOptName( Arg& arg, std::string const& optName ) - { - if( optName.empty() ) - return; - if( Detail::startsWith( optName, "--" ) ) { - if( !arg.longName.empty() ) - throw std::logic_error( "Only one long opt may be specified. '" - + arg.longName - + "' already specified, now attempting to add '" - + optName + "'" ); - arg.longName = optName.substr( 2 ); - } - else if( Detail::startsWith( optName, "-" ) ) - arg.shortNames.push_back( optName.substr( 1 ) ); - else - throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); - } - friend void setPositionalArg( Arg& arg, int position ) - { - arg.position = position; - } - - class ArgBuilder { - public: - ArgBuilder( Arg* arg ) : m_arg( arg ) {} - - // Bind a non-boolean data member (requires placeholder string) - template - void bind( M C::* field, std::string const& placeholder ) { - m_arg->boundField = new Detail::BoundDataMember( field ); - m_arg->placeholder = placeholder; - } - // Bind a boolean data member (no placeholder required) - template - void bind( bool C::* field ) { - m_arg->boundField = new Detail::BoundDataMember( field ); - } - - // Bind a method taking a single, non-boolean argument (requires a placeholder string) - template - void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { - m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); - m_arg->placeholder = placeholder; - } - - // Bind a method taking a single, boolean argument (no placeholder string required) - template - void bind( void (C::* unaryMethod)( bool ) ) { - m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); - } - - // Bind a method that takes no arguments (will be called if opt is present) - template - void bind( void (C::* nullaryMethod)() ) { - m_arg->boundField = new Detail::BoundNullaryMethod( nullaryMethod ); - } - - // Bind a free function taking a single argument - the object to operate on (no placeholder string required) - template - void bind( void (* unaryFunction)( C& ) ) { - m_arg->boundField = new Detail::BoundUnaryFunction( unaryFunction ); - } - - // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) - template - void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { - m_arg->boundField = new Detail::BoundBinaryFunction( binaryFunction ); - m_arg->placeholder = placeholder; - } - - ArgBuilder& describe( std::string const& description ) { - m_arg->description = description; - return *this; - } - ArgBuilder& detail( std::string const& detail ) { - m_arg->detail = detail; - return *this; - } - - protected: - Arg* m_arg; - }; - - class OptBuilder : public ArgBuilder { - public: - OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} - OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} - - OptBuilder& operator[]( std::string const& optName ) { - addOptName( *ArgBuilder::m_arg, optName ); - return *this; - } - }; - - public: - - CommandLine() - : m_boundProcessName( new Detail::NullBinder() ), - m_highestSpecifiedArgPosition( 0 ), - m_throwOnUnrecognisedTokens( false ) - {} - CommandLine( CommandLine const& other ) - : m_boundProcessName( other.m_boundProcessName ), - m_options ( other.m_options ), - m_positionalArgs( other.m_positionalArgs ), - m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), - m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) - { - if( other.m_floatingArg.get() ) - m_floatingArg.reset( new Arg( *other.m_floatingArg ) ); - } - - CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { - m_throwOnUnrecognisedTokens = shouldThrow; - return *this; - } - - OptBuilder operator[]( std::string const& optName ) { - m_options.push_back( Arg() ); - addOptName( m_options.back(), optName ); - OptBuilder builder( &m_options.back() ); - return builder; - } - - ArgBuilder operator[]( int position ) { - m_positionalArgs.insert( std::make_pair( position, Arg() ) ); - if( position > m_highestSpecifiedArgPosition ) - m_highestSpecifiedArgPosition = position; - setPositionalArg( m_positionalArgs[position], position ); - ArgBuilder builder( &m_positionalArgs[position] ); - return builder; - } - - // Invoke this with the _ instance - ArgBuilder operator[]( UnpositionalTag ) { - if( m_floatingArg.get() ) - throw std::logic_error( "Only one unpositional argument can be added" ); - m_floatingArg.reset( new Arg() ); - ArgBuilder builder( m_floatingArg.get() ); - return builder; - } - - template - void bindProcessName( M C::* field ) { - m_boundProcessName = new Detail::BoundDataMember( field ); - } - template - void bindProcessName( void (C::*_unaryMethod)( M ) ) { - m_boundProcessName = new Detail::BoundUnaryMethod( _unaryMethod ); - } - - void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { - typename std::vector::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; - std::size_t maxWidth = 0; - for( it = itBegin; it != itEnd; ++it ) - maxWidth = (std::max)( maxWidth, it->commands().size() ); - - for( it = itBegin; it != itEnd; ++it ) { - Detail::Text usage( it->commands(), Detail::TextAttributes() - .setWidth( maxWidth+indent ) - .setIndent( indent ) ); - Detail::Text desc( it->description, Detail::TextAttributes() - .setWidth( width - maxWidth - 3 ) ); - - for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { - std::string usageCol = i < usage.size() ? usage[i] : ""; - os << usageCol; - - if( i < desc.size() && !desc[i].empty() ) - os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) - << desc[i]; - os << "\n"; - } - } - } - std::string optUsage() const { - std::ostringstream oss; - optUsage( oss ); - return oss.str(); - } - - void argSynopsis( std::ostream& os ) const { - for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { - if( i > 1 ) - os << " "; - typename std::map::const_iterator it = m_positionalArgs.find( i ); - if( it != m_positionalArgs.end() ) - os << "<" << it->second.placeholder << ">"; - else if( m_floatingArg.get() ) - os << "<" << m_floatingArg->placeholder << ">"; - else - throw std::logic_error( "non consecutive positional arguments with no floating args" ); - } - // !TBD No indication of mandatory args - if( m_floatingArg.get() ) { - if( m_highestSpecifiedArgPosition > 1 ) - os << " "; - os << "[<" << m_floatingArg->placeholder << "> ...]"; - } - } - std::string argSynopsis() const { - std::ostringstream oss; - argSynopsis( oss ); - return oss.str(); - } - - void usage( std::ostream& os, std::string const& procName ) const { - validate(); - os << "usage:\n " << procName << " "; - argSynopsis( os ); - if( !m_options.empty() ) { - os << " [options]\n\nwhere options are: \n"; - optUsage( os, 2 ); - } - os << "\n"; - } - std::string usage( std::string const& procName ) const { - std::ostringstream oss; - usage( oss, procName ); - return oss.str(); - } - - ConfigT parse( int argc, char const * const * argv ) const { - ConfigT config; - parseInto( argc, argv, config ); - return config; - } - - std::vector parseInto( int argc, char const * const * argv, ConfigT& config ) const { - std::string processName = argv[0]; - std::size_t lastSlash = processName.find_last_of( "/\\" ); - if( lastSlash != std::string::npos ) - processName = processName.substr( lastSlash+1 ); - m_boundProcessName.set( config, processName ); - std::vector tokens; - Parser parser; - parser.parseIntoTokens( argc, argv, tokens ); - return populate( tokens, config ); - } - - std::vector populate( std::vector const& tokens, ConfigT& config ) const { - validate(); - std::vector unusedTokens = populateOptions( tokens, config ); - unusedTokens = populateFixedArgs( unusedTokens, config ); - unusedTokens = populateFloatingArgs( unusedTokens, config ); - return unusedTokens; - } - - std::vector populateOptions( std::vector const& tokens, ConfigT& config ) const { - std::vector unusedTokens; - std::vector errors; - for( std::size_t i = 0; i < tokens.size(); ++i ) { - Parser::Token const& token = tokens[i]; - typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); - for(; it != itEnd; ++it ) { - Arg const& arg = *it; - - try { - if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || - ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { - if( arg.takesArg() ) { - if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) - errors.push_back( "Expected argument to option: " + token.data ); - else - arg.boundField.set( config, tokens[++i].data ); - } - else { - arg.boundField.setFlag( config ); - } - break; - } - } - catch( std::exception& ex ) { - errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); - } - } - if( it == itEnd ) { - if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) - unusedTokens.push_back( token ); - else if( errors.empty() && m_throwOnUnrecognisedTokens ) - errors.push_back( "unrecognised option: " + token.data ); - } - } - if( !errors.empty() ) { - std::ostringstream oss; - for( std::vector::const_iterator it = errors.begin(), itEnd = errors.end(); - it != itEnd; - ++it ) { - if( it != errors.begin() ) - oss << "\n"; - oss << *it; - } - throw std::runtime_error( oss.str() ); - } - return unusedTokens; - } - std::vector populateFixedArgs( std::vector const& tokens, ConfigT& config ) const { - std::vector unusedTokens; - int position = 1; - for( std::size_t i = 0; i < tokens.size(); ++i ) { - Parser::Token const& token = tokens[i]; - typename std::map::const_iterator it = m_positionalArgs.find( position ); - if( it != m_positionalArgs.end() ) - it->second.boundField.set( config, token.data ); - else - unusedTokens.push_back( token ); - if( token.type == Parser::Token::Positional ) - position++; - } - return unusedTokens; - } - std::vector populateFloatingArgs( std::vector const& tokens, ConfigT& config ) const { - if( !m_floatingArg.get() ) - return tokens; - std::vector unusedTokens; - for( std::size_t i = 0; i < tokens.size(); ++i ) { - Parser::Token const& token = tokens[i]; - if( token.type == Parser::Token::Positional ) - m_floatingArg->boundField.set( config, token.data ); - else - unusedTokens.push_back( token ); - } - return unusedTokens; - } - - void validate() const - { - if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) - throw std::logic_error( "No options or arguments specified" ); - - for( typename std::vector::const_iterator it = m_options.begin(), - itEnd = m_options.end(); - it != itEnd; ++it ) - it->validate(); - } - - private: - Detail::BoundArgFunction m_boundProcessName; - std::vector m_options; - std::map m_positionalArgs; - ArgAutoPtr m_floatingArg; - int m_highestSpecifiedArgPosition; - bool m_throwOnUnrecognisedTokens; - }; - -} // end namespace Clara - -STITCH_CLARA_CLOSE_NAMESPACE -#undef STITCH_CLARA_OPEN_NAMESPACE -#undef STITCH_CLARA_CLOSE_NAMESPACE - -#endif // TWOBLUECUBES_CLARA_H_INCLUDED -#undef STITCH_CLARA_OPEN_NAMESPACE - -// Restore Clara's value for console width, if present -#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH -#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH -#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH -#endif - -#include - -namespace Catch { - - inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } - inline void abortAfterX( ConfigData& config, int x ) { - if( x < 1 ) - throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); - config.abortAfter = x; - } - inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } - - inline void addWarning( ConfigData& config, std::string const& _warning ) { - if( _warning == "NoAssertions" ) - config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); - else - throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" ); - } - inline void setOrder( ConfigData& config, std::string const& order ) { - if( startsWith( "declared", order ) ) - config.runOrder = RunTests::InDeclarationOrder; - else if( startsWith( "lexical", order ) ) - config.runOrder = RunTests::InLexicographicalOrder; - else if( startsWith( "random", order ) ) - config.runOrder = RunTests::InRandomOrder; - else - throw std::runtime_error( "Unrecognised ordering: '" + order + "'" ); - } - inline void setRngSeed( ConfigData& config, std::string const& seed ) { - if( seed == "time" ) { - config.rngSeed = static_cast( std::time(0) ); - } - else { - std::stringstream ss; - ss << seed; - ss >> config.rngSeed; - if( ss.fail() ) - throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" ); - } - } - inline void setVerbosity( ConfigData& config, int level ) { - // !TBD: accept strings? - config.verbosity = static_cast( level ); - } - inline void setShowDurations( ConfigData& config, bool _showDurations ) { - config.showDurations = _showDurations - ? ShowDurations::Always - : ShowDurations::Never; - } - inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { - std::ifstream f( _filename.c_str() ); - if( !f.is_open() ) - throw std::domain_error( "Unable to load input file: " + _filename ); - - std::string line; - while( std::getline( f, line ) ) { - line = trim(line); - if( !line.empty() && !startsWith( line, "#" ) ) - addTestOrTags( config, "\"" + line + "\"," ); - } - } - - inline Clara::CommandLine makeCommandLineParser() { - - using namespace Clara; - CommandLine cli; - - cli.bindProcessName( &ConfigData::processName ); - - cli["-?"]["-h"]["--help"] - .describe( "display usage information" ) - .bind( &ConfigData::showHelp ); - - cli["-l"]["--list-tests"] - .describe( "list all/matching test cases" ) - .bind( &ConfigData::listTests ); - - cli["-t"]["--list-tags"] - .describe( "list all/matching tags" ) - .bind( &ConfigData::listTags ); - - cli["-s"]["--success"] - .describe( "include successful tests in output" ) - .bind( &ConfigData::showSuccessfulTests ); - - cli["-b"]["--break"] - .describe( "break into debugger on failure" ) - .bind( &ConfigData::shouldDebugBreak ); - - cli["-e"]["--nothrow"] - .describe( "skip exception tests" ) - .bind( &ConfigData::noThrow ); - - cli["-i"]["--invisibles"] - .describe( "show invisibles (tabs, newlines)" ) - .bind( &ConfigData::showInvisibles ); - - cli["-o"]["--out"] - .describe( "output filename" ) - .bind( &ConfigData::outputFilename, "filename" ); - - cli["-r"]["--reporter"] -// .placeholder( "name[:filename]" ) - .describe( "reporter to use (defaults to console)" ) - .bind( &ConfigData::reporterName, "name" ); - - cli["-n"]["--name"] - .describe( "suite name" ) - .bind( &ConfigData::name, "name" ); - - cli["-a"]["--abort"] - .describe( "abort at first failure" ) - .bind( &abortAfterFirst ); - - cli["-x"]["--abortx"] - .describe( "abort after x failures" ) - .bind( &abortAfterX, "no. failures" ); - - cli["-w"]["--warn"] - .describe( "enable warnings" ) - .bind( &addWarning, "warning name" ); - -// - needs updating if reinstated -// cli.into( &setVerbosity ) -// .describe( "level of verbosity (0=no output)" ) -// .shortOpt( "v") -// .longOpt( "verbosity" ) -// .placeholder( "level" ); - - cli[_] - .describe( "which test or tests to use" ) - .bind( &addTestOrTags, "test name, pattern or tags" ); - - cli["-d"]["--durations"] - .describe( "show test durations" ) - .bind( &setShowDurations, "yes/no" ); - - cli["-f"]["--input-file"] - .describe( "load test names to run from a file" ) - .bind( &loadTestNamesFromFile, "filename" ); - - // Less common commands which don't have a short form - cli["--list-test-names-only"] - .describe( "list all/matching test cases names only" ) - .bind( &ConfigData::listTestNamesOnly ); - - cli["--list-reporters"] - .describe( "list all reporters" ) - .bind( &ConfigData::listReporters ); - - cli["--order"] - .describe( "test case order (defaults to decl)" ) - .bind( &setOrder, "decl|lex|rand" ); - - cli["--rng-seed"] - .describe( "set a specific seed for random numbers" ) - .bind( &setRngSeed, "'time'|number" ); - - return cli; - } - -} // end namespace Catch - -// #included from: internal/catch_list.hpp -#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED - -// #included from: catch_text.h -#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED - -#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH - -#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch -// #included from: ../external/tbc_text_format.h -// Only use header guard if we are not using an outer namespace -#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE -# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED -# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED -# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED -# endif -# else -# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED -# endif -#endif -#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED -#include -#include -#include - -// Use optional outer namespace -#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE -namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { -#endif - -namespace Tbc { - -#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH - const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; -#else - const unsigned int consoleWidth = 80; -#endif - - struct TextAttributes { - TextAttributes() - : initialIndent( std::string::npos ), - indent( 0 ), - width( consoleWidth-1 ), - tabChar( '\t' ) - {} - - TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } - TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } - TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } - TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } - - std::size_t initialIndent; // indent of first line, or npos - std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos - std::size_t width; // maximum width of text, including indent. Longer text will wrap - char tabChar; // If this char is seen the indent is changed to current pos - }; - - class Text { - public: - Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) - : attr( _attr ) - { - std::string wrappableChars = " [({.,/|\\-"; - std::size_t indent = _attr.initialIndent != std::string::npos - ? _attr.initialIndent - : _attr.indent; - std::string remainder = _str; - - while( !remainder.empty() ) { - if( lines.size() >= 1000 ) { - lines.push_back( "... message truncated due to excessive size" ); - return; - } - std::size_t tabPos = std::string::npos; - std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); - std::size_t pos = remainder.find_first_of( '\n' ); - if( pos <= width ) { - width = pos; - } - pos = remainder.find_last_of( _attr.tabChar, width ); - if( pos != std::string::npos ) { - tabPos = pos; - if( remainder[width] == '\n' ) - width--; - remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); - } - - if( width == remainder.size() ) { - spliceLine( indent, remainder, width ); - } - else if( remainder[width] == '\n' ) { - spliceLine( indent, remainder, width ); - if( width <= 1 || remainder.size() != 1 ) - remainder = remainder.substr( 1 ); - indent = _attr.indent; - } - else { - pos = remainder.find_last_of( wrappableChars, width ); - if( pos != std::string::npos && pos > 0 ) { - spliceLine( indent, remainder, pos ); - if( remainder[0] == ' ' ) - remainder = remainder.substr( 1 ); - } - else { - spliceLine( indent, remainder, width-1 ); - lines.back() += "-"; - } - if( lines.size() == 1 ) - indent = _attr.indent; - if( tabPos != std::string::npos ) - indent += tabPos; - } - } - } - - void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { - lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); - _remainder = _remainder.substr( _pos ); - } - - typedef std::vector::const_iterator const_iterator; - - const_iterator begin() const { return lines.begin(); } - const_iterator end() const { return lines.end(); } - std::string const& last() const { return lines.back(); } - std::size_t size() const { return lines.size(); } - std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } - std::string toString() const { - std::ostringstream oss; - oss << *this; - return oss.str(); - } - - inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { - for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); - it != itEnd; ++it ) { - if( it != _text.begin() ) - _stream << "\n"; - _stream << *it; - } - return _stream; - } - - private: - std::string str; - TextAttributes attr; - std::vector lines; - }; - -} // end namespace Tbc - -#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE -} // end outer namespace -#endif - -#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED -#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE - -namespace Catch { - using Tbc::Text; - using Tbc::TextAttributes; -} - -// #included from: catch_console_colour.hpp -#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED - -namespace Catch { - - struct Colour { - enum Code { - None = 0, - - White, - Red, - Green, - Blue, - Cyan, - Yellow, - Grey, - - Bright = 0x10, - - BrightRed = Bright | Red, - BrightGreen = Bright | Green, - LightGrey = Bright | Grey, - BrightWhite = Bright | White, - - // By intention - FileName = LightGrey, - Warning = Yellow, - ResultError = BrightRed, - ResultSuccess = BrightGreen, - ResultExpectedFailure = Warning, - - Error = BrightRed, - Success = Green, - - OriginalExpression = Cyan, - ReconstructedExpression = Yellow, - - SecondaryText = LightGrey, - Headers = White - }; - - // Use constructed object for RAII guard - Colour( Code _colourCode ); - Colour( Colour const& other ); - ~Colour(); - - // Use static method for one-shot changes - static void use( Code _colourCode ); - - private: - bool m_moved; - }; - - inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } - -} // end namespace Catch - -// #included from: catch_interfaces_reporter.h -#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED - -#include -#include -#include -#include - -namespace Catch -{ - struct ReporterConfig { - explicit ReporterConfig( Ptr const& _fullConfig ) - : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} - - ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) - : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} - - std::ostream& stream() const { return *m_stream; } - Ptr fullConfig() const { return m_fullConfig; } - - private: - std::ostream* m_stream; - Ptr m_fullConfig; - }; - - struct ReporterPreferences { - ReporterPreferences() - : shouldRedirectStdOut( false ) - {} - - bool shouldRedirectStdOut; - }; - - template - struct LazyStat : Option { - LazyStat() : used( false ) {} - LazyStat& operator=( T const& _value ) { - Option::operator=( _value ); - used = false; - return *this; - } - void reset() { - Option::reset(); - used = false; - } - bool used; - }; - - struct TestRunInfo { - TestRunInfo( std::string const& _name ) : name( _name ) {} - std::string name; - }; - struct GroupInfo { - GroupInfo( std::string const& _name, - std::size_t _groupIndex, - std::size_t _groupsCount ) - : name( _name ), - groupIndex( _groupIndex ), - groupsCounts( _groupsCount ) - {} - - std::string name; - std::size_t groupIndex; - std::size_t groupsCounts; - }; - - struct AssertionStats { - AssertionStats( AssertionResult const& _assertionResult, - std::vector const& _infoMessages, - Totals const& _totals ) - : assertionResult( _assertionResult ), - infoMessages( _infoMessages ), - totals( _totals ) - { - if( assertionResult.hasMessage() ) { - // Copy message into messages list. - // !TBD This should have been done earlier, somewhere - MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); - builder << assertionResult.getMessage(); - builder.m_info.message = builder.m_stream.str(); - - infoMessages.push_back( builder.m_info ); - } - } - virtual ~AssertionStats(); - -# ifdef CATCH_CPP11_OR_GREATER - AssertionStats( AssertionStats const& ) = default; - AssertionStats( AssertionStats && ) = default; - AssertionStats& operator = ( AssertionStats const& ) = default; - AssertionStats& operator = ( AssertionStats && ) = default; -# endif - - AssertionResult assertionResult; - std::vector infoMessages; - Totals totals; - }; - - struct SectionStats { - SectionStats( SectionInfo const& _sectionInfo, - Counts const& _assertions, - double _durationInSeconds, - bool _missingAssertions ) - : sectionInfo( _sectionInfo ), - assertions( _assertions ), - durationInSeconds( _durationInSeconds ), - missingAssertions( _missingAssertions ) - {} - virtual ~SectionStats(); -# ifdef CATCH_CPP11_OR_GREATER - SectionStats( SectionStats const& ) = default; - SectionStats( SectionStats && ) = default; - SectionStats& operator = ( SectionStats const& ) = default; - SectionStats& operator = ( SectionStats && ) = default; -# endif - - SectionInfo sectionInfo; - Counts assertions; - double durationInSeconds; - bool missingAssertions; - }; - - struct TestCaseStats { - TestCaseStats( TestCaseInfo const& _testInfo, - Totals const& _totals, - std::string const& _stdOut, - std::string const& _stdErr, - bool _aborting ) - : testInfo( _testInfo ), - totals( _totals ), - stdOut( _stdOut ), - stdErr( _stdErr ), - aborting( _aborting ) - {} - virtual ~TestCaseStats(); - -# ifdef CATCH_CPP11_OR_GREATER - TestCaseStats( TestCaseStats const& ) = default; - TestCaseStats( TestCaseStats && ) = default; - TestCaseStats& operator = ( TestCaseStats const& ) = default; - TestCaseStats& operator = ( TestCaseStats && ) = default; -# endif - - TestCaseInfo testInfo; - Totals totals; - std::string stdOut; - std::string stdErr; - bool aborting; - }; - - struct TestGroupStats { - TestGroupStats( GroupInfo const& _groupInfo, - Totals const& _totals, - bool _aborting ) - : groupInfo( _groupInfo ), - totals( _totals ), - aborting( _aborting ) - {} - TestGroupStats( GroupInfo const& _groupInfo ) - : groupInfo( _groupInfo ), - aborting( false ) - {} - virtual ~TestGroupStats(); - -# ifdef CATCH_CPP11_OR_GREATER - TestGroupStats( TestGroupStats const& ) = default; - TestGroupStats( TestGroupStats && ) = default; - TestGroupStats& operator = ( TestGroupStats const& ) = default; - TestGroupStats& operator = ( TestGroupStats && ) = default; -# endif - - GroupInfo groupInfo; - Totals totals; - bool aborting; - }; - - struct TestRunStats { - TestRunStats( TestRunInfo const& _runInfo, - Totals const& _totals, - bool _aborting ) - : runInfo( _runInfo ), - totals( _totals ), - aborting( _aborting ) - {} - virtual ~TestRunStats(); - -# ifndef CATCH_CPP11_OR_GREATER - TestRunStats( TestRunStats const& _other ) - : runInfo( _other.runInfo ), - totals( _other.totals ), - aborting( _other.aborting ) - {} -# else - TestRunStats( TestRunStats const& ) = default; - TestRunStats( TestRunStats && ) = default; - TestRunStats& operator = ( TestRunStats const& ) = default; - TestRunStats& operator = ( TestRunStats && ) = default; -# endif - - TestRunInfo runInfo; - Totals totals; - bool aborting; - }; - - struct IStreamingReporter : IShared { - virtual ~IStreamingReporter(); - - // Implementing class must also provide the following static method: - // static std::string getDescription(); - - virtual ReporterPreferences getPreferences() const = 0; - - virtual void noMatchingTestCases( std::string const& spec ) = 0; - - virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; - virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; - - virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; - virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; - - virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; - - // The return value indicates if the messages buffer should be cleared: - virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; - virtual void sectionEnded( SectionStats const& sectionStats ) = 0; - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; - virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; - - virtual void skipTest( TestCaseInfo const& testInfo ) = 0; - }; - - struct IReporterFactory { - virtual ~IReporterFactory(); - virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; - virtual std::string getDescription() const = 0; - }; - - struct IReporterRegistry { - typedef std::map FactoryMap; - - virtual ~IReporterRegistry(); - virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; - virtual FactoryMap const& getFactories() const = 0; - }; - -} - -#include -#include - -namespace Catch { - - inline std::size_t listTests( Config const& config ) { - - TestSpec testSpec = config.testSpec(); - if( config.testSpec().hasFilters() ) - Catch::cout() << "Matching test cases:\n"; - else { - Catch::cout() << "All available test cases:\n"; - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); - } - - std::size_t matchedTests = 0; - TextAttributes nameAttr, tagsAttr; - nameAttr.setInitialIndent( 2 ).setIndent( 4 ); - tagsAttr.setIndent( 6 ); - - std::vector matchedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); - for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); - it != itEnd; - ++it ) { - matchedTests++; - TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); - Colour::Code colour = testCaseInfo.isHidden() - ? Colour::SecondaryText - : Colour::None; - Colour colourGuard( colour ); - - Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; - if( !testCaseInfo.tags.empty() ) - Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; - } - - if( !config.testSpec().hasFilters() ) - Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl; - else - Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl; - return matchedTests; - } - - inline std::size_t listTestsNamesOnly( Config const& config ) { - TestSpec testSpec = config.testSpec(); - if( !config.testSpec().hasFilters() ) - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); - std::size_t matchedTests = 0; - std::vector matchedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); - for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); - it != itEnd; - ++it ) { - matchedTests++; - TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); - Catch::cout() << testCaseInfo.name << std::endl; - } - return matchedTests; - } - - struct TagInfo { - TagInfo() : count ( 0 ) {} - void add( std::string const& spelling ) { - ++count; - spellings.insert( spelling ); - } - std::string all() const { - std::string out; - for( std::set::const_iterator it = spellings.begin(), itEnd = spellings.end(); - it != itEnd; - ++it ) - out += "[" + *it + "]"; - return out; - } - std::set spellings; - std::size_t count; - }; - - inline std::size_t listTags( Config const& config ) { - TestSpec testSpec = config.testSpec(); - if( config.testSpec().hasFilters() ) - Catch::cout() << "Tags for matching test cases:\n"; - else { - Catch::cout() << "All available tags:\n"; - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); - } - - std::map tagCounts; - - std::vector matchedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); - for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); - it != itEnd; - ++it ) { - for( std::set::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), - tagItEnd = it->getTestCaseInfo().tags.end(); - tagIt != tagItEnd; - ++tagIt ) { - std::string tagName = *tagIt; - std::string lcaseTagName = toLower( tagName ); - std::map::iterator countIt = tagCounts.find( lcaseTagName ); - if( countIt == tagCounts.end() ) - countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; - countIt->second.add( tagName ); - } - } - - for( std::map::const_iterator countIt = tagCounts.begin(), - countItEnd = tagCounts.end(); - countIt != countItEnd; - ++countIt ) { - std::ostringstream oss; - oss << " " << std::setw(2) << countIt->second.count << " "; - Text wrapper( countIt->second.all(), TextAttributes() - .setInitialIndent( 0 ) - .setIndent( oss.str().size() ) - .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); - Catch::cout() << oss.str() << wrapper << "\n"; - } - Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl; - return tagCounts.size(); - } - - inline std::size_t listReporters( Config const& /*config*/ ) { - Catch::cout() << "Available reporters:\n"; - IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); - IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; - std::size_t maxNameLen = 0; - for(it = itBegin; it != itEnd; ++it ) - maxNameLen = (std::max)( maxNameLen, it->first.size() ); - - for(it = itBegin; it != itEnd; ++it ) { - Text wrapper( it->second->getDescription(), TextAttributes() - .setInitialIndent( 0 ) - .setIndent( 7+maxNameLen ) - .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); - Catch::cout() << " " - << it->first - << ":" - << std::string( maxNameLen - it->first.size() + 2, ' ' ) - << wrapper << "\n"; - } - Catch::cout() << std::endl; - return factories.size(); - } - - inline Option list( Config const& config ) { - Option listedCount; - if( config.listTests() ) - listedCount = listedCount.valueOr(0) + listTests( config ); - if( config.listTestNamesOnly() ) - listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); - if( config.listTags() ) - listedCount = listedCount.valueOr(0) + listTags( config ); - if( config.listReporters() ) - listedCount = listedCount.valueOr(0) + listReporters( config ); - return listedCount; - } - -} // end namespace Catch - -// #included from: internal/catch_runner_impl.hpp -#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED - -// #included from: catch_test_case_tracker.hpp -#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED - -#include -#include -#include - -namespace Catch { -namespace SectionTracking { - - class TrackedSection { - - typedef std::map TrackedSections; - - public: - enum RunState { - NotStarted, - Executing, - ExecutingChildren, - Completed - }; - - TrackedSection( std::string const& name, TrackedSection* parent ) - : m_name( name ), m_runState( NotStarted ), m_parent( parent ) - {} - - RunState runState() const { return m_runState; } - - TrackedSection* findChild( std::string const& childName ) { - TrackedSections::iterator it = m_children.find( childName ); - return it != m_children.end() - ? &it->second - : NULL; - } - TrackedSection* acquireChild( std::string const& childName ) { - if( TrackedSection* child = findChild( childName ) ) - return child; - m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) ); - return findChild( childName ); - } - void enter() { - if( m_runState == NotStarted ) - m_runState = Executing; - } - void leave() { - for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end(); - it != itEnd; - ++it ) - if( it->second.runState() != Completed ) { - m_runState = ExecutingChildren; - return; - } - m_runState = Completed; - } - TrackedSection* getParent() { - return m_parent; - } - bool hasChildren() const { - return !m_children.empty(); - } - - private: - std::string m_name; - RunState m_runState; - TrackedSections m_children; - TrackedSection* m_parent; - - }; - - class TestCaseTracker { - public: - TestCaseTracker( std::string const& testCaseName ) - : m_testCase( testCaseName, NULL ), - m_currentSection( &m_testCase ), - m_completedASectionThisRun( false ) - {} - - bool enterSection( std::string const& name ) { - TrackedSection* child = m_currentSection->acquireChild( name ); - if( m_completedASectionThisRun || child->runState() == TrackedSection::Completed ) - return false; - - m_currentSection = child; - m_currentSection->enter(); - return true; - } - void leaveSection() { - m_currentSection->leave(); - m_currentSection = m_currentSection->getParent(); - assert( m_currentSection != NULL ); - m_completedASectionThisRun = true; - } - - bool currentSectionHasChildren() const { - return m_currentSection->hasChildren(); - } - bool isCompleted() const { - return m_testCase.runState() == TrackedSection::Completed; - } - - class Guard { - public: - Guard( TestCaseTracker& tracker ) : m_tracker( tracker ) { - m_tracker.enterTestCase(); - } - ~Guard() { - m_tracker.leaveTestCase(); - } - private: - Guard( Guard const& ); - void operator = ( Guard const& ); - TestCaseTracker& m_tracker; - }; - - private: - void enterTestCase() { - m_currentSection = &m_testCase; - m_completedASectionThisRun = false; - m_testCase.enter(); - } - void leaveTestCase() { - m_testCase.leave(); - } - - TrackedSection m_testCase; - TrackedSection* m_currentSection; - bool m_completedASectionThisRun; - }; - -} // namespace SectionTracking - -using SectionTracking::TestCaseTracker; - -} // namespace Catch - -// #included from: catch_fatal_condition.hpp -#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED - -namespace Catch { - - // Report the error condition then exit the process - inline void fatal( std::string const& message, int exitCode ) { - IContext& context = Catch::getCurrentContext(); - IResultCapture* resultCapture = context.getResultCapture(); - resultCapture->handleFatalErrorCondition( message ); - - if( Catch::alwaysTrue() ) // avoids "no return" warnings - exit( exitCode ); - } - -} // namespace Catch - -#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// - -namespace Catch { - - struct FatalConditionHandler { - void reset() {} - }; - -} // namespace Catch - -#else // Not Windows - assumed to be POSIX compatible ////////////////////////// - -#include - -namespace Catch { - - struct SignalDefs { int id; const char* name; }; - extern SignalDefs signalDefs[]; - SignalDefs signalDefs[] = { - { SIGINT, "SIGINT - Terminal interrupt signal" }, - { SIGILL, "SIGILL - Illegal instruction signal" }, - { SIGFPE, "SIGFPE - Floating point error signal" }, - { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, - { SIGTERM, "SIGTERM - Termination request signal" }, - { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } - }; - - struct FatalConditionHandler { - - static void handleSignal( int sig ) { - for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) - if( sig == signalDefs[i].id ) - fatal( signalDefs[i].name, -sig ); - fatal( "", -sig ); - } - - FatalConditionHandler() : m_isSet( true ) { - for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) - signal( signalDefs[i].id, handleSignal ); - } - ~FatalConditionHandler() { - reset(); - } - void reset() { - if( m_isSet ) { - for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) - signal( signalDefs[i].id, SIG_DFL ); - m_isSet = false; - } - } - - bool m_isSet; - }; - -} // namespace Catch - -#endif // not Windows - -#include -#include - -namespace Catch { - - class StreamRedirect { - - public: - StreamRedirect( std::ostream& stream, std::string& targetString ) - : m_stream( stream ), - m_prevBuf( stream.rdbuf() ), - m_targetString( targetString ) - { - stream.rdbuf( m_oss.rdbuf() ); - } - - ~StreamRedirect() { - m_targetString += m_oss.str(); - m_stream.rdbuf( m_prevBuf ); - } - - private: - std::ostream& m_stream; - std::streambuf* m_prevBuf; - std::ostringstream m_oss; - std::string& m_targetString; - }; - - /////////////////////////////////////////////////////////////////////////// - - class RunContext : public IResultCapture, public IRunner { - - RunContext( RunContext const& ); - void operator =( RunContext const& ); - - public: - - explicit RunContext( Ptr const& config, Ptr const& reporter ) - : m_runInfo( config->name() ), - m_context( getCurrentMutableContext() ), - m_activeTestCase( NULL ), - m_config( config ), - m_reporter( reporter ), - m_prevRunner( m_context.getRunner() ), - m_prevResultCapture( m_context.getResultCapture() ), - m_prevConfig( m_context.getConfig() ) - { - m_context.setRunner( this ); - m_context.setConfig( m_config ); - m_context.setResultCapture( this ); - m_reporter->testRunStarting( m_runInfo ); - } - - virtual ~RunContext() { - m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); - m_context.setRunner( m_prevRunner ); - m_context.setConfig( NULL ); - m_context.setResultCapture( m_prevResultCapture ); - m_context.setConfig( m_prevConfig ); - } - - void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { - m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); - } - void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { - m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); - } - - Totals runTest( TestCase const& testCase ) { - Totals prevTotals = m_totals; - - std::string redirectedCout; - std::string redirectedCerr; - - TestCaseInfo testInfo = testCase.getTestCaseInfo(); - - m_reporter->testCaseStarting( testInfo ); - - m_activeTestCase = &testCase; - m_testCaseTracker = TestCaseTracker( testInfo.name ); - - do { - do { - runCurrentTest( redirectedCout, redirectedCerr ); - } - while( !m_testCaseTracker->isCompleted() && !aborting() ); - } - while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); - - Totals deltaTotals = m_totals.delta( prevTotals ); - m_totals.testCases += deltaTotals.testCases; - m_reporter->testCaseEnded( TestCaseStats( testInfo, - deltaTotals, - redirectedCout, - redirectedCerr, - aborting() ) ); - - m_activeTestCase = NULL; - m_testCaseTracker.reset(); - - return deltaTotals; - } - - Ptr config() const { - return m_config; - } - - private: // IResultCapture - - virtual void assertionEnded( AssertionResult const& result ) { - if( result.getResultType() == ResultWas::Ok ) { - m_totals.assertions.passed++; - } - else if( !result.isOk() ) { - m_totals.assertions.failed++; - } - - if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) ) - m_messages.clear(); - - // Reset working state - m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); - m_lastResult = result; - } - - virtual bool sectionStarted ( - SectionInfo const& sectionInfo, - Counts& assertions - ) - { - std::ostringstream oss; - oss << sectionInfo.name << "@" << sectionInfo.lineInfo; - - if( !m_testCaseTracker->enterSection( oss.str() ) ) - return false; - - m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; - - m_reporter->sectionStarting( sectionInfo ); - - assertions = m_totals.assertions; - - return true; - } - bool testForMissingAssertions( Counts& assertions ) { - if( assertions.total() != 0 || - !m_config->warnAboutMissingAssertions() || - m_testCaseTracker->currentSectionHasChildren() ) - return false; - m_totals.assertions.failed++; - assertions.failed++; - return true; - } - - virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) { - if( std::uncaught_exception() ) { - m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) ); - return; - } - - Counts assertions = m_totals.assertions - prevAssertions; - bool missingAssertions = testForMissingAssertions( assertions ); - - m_testCaseTracker->leaveSection(); - - m_reporter->sectionEnded( SectionStats( info, assertions, _durationInSeconds, missingAssertions ) ); - m_messages.clear(); - } - - virtual void pushScopedMessage( MessageInfo const& message ) { - m_messages.push_back( message ); - } - - virtual void popScopedMessage( MessageInfo const& message ) { - m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); - } - - virtual std::string getCurrentTestName() const { - return m_activeTestCase - ? m_activeTestCase->getTestCaseInfo().name - : ""; - } - - virtual const AssertionResult* getLastResult() const { - return &m_lastResult; - } - - virtual void handleFatalErrorCondition( std::string const& message ) { - ResultBuilder resultBuilder = makeUnexpectedResultBuilder(); - resultBuilder.setResultType( ResultWas::FatalErrorCondition ); - resultBuilder << message; - resultBuilder.captureExpression(); - - handleUnfinishedSections(); - - // Recreate section for test case (as we will lose the one that was in scope) - TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); - SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); - - Counts assertions; - assertions.failed = 1; - SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false ); - m_reporter->sectionEnded( testCaseSectionStats ); - - TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo(); - - Totals deltaTotals; - deltaTotals.testCases.failed = 1; - m_reporter->testCaseEnded( TestCaseStats( testInfo, - deltaTotals, - "", - "", - false ) ); - m_totals.testCases.failed++; - testGroupEnded( "", m_totals, 1, 1 ); - m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); - } - - public: - // !TBD We need to do this another way! - bool aborting() const { - return m_totals.assertions.failed == static_cast( m_config->abortAfter() ); - } - - private: - - void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { - TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); - SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); - m_reporter->sectionStarting( testCaseSection ); - Counts prevAssertions = m_totals.assertions; - double duration = 0; - try { - m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); - TestCaseTracker::Guard guard( *m_testCaseTracker ); - - Timer timer; - timer.start(); - if( m_reporter->getPreferences().shouldRedirectStdOut ) { - StreamRedirect coutRedir( Catch::cout(), redirectedCout ); - StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr ); - invokeActiveTestCase(); - } - else { - invokeActiveTestCase(); - } - duration = timer.getElapsedSeconds(); - } - catch( TestFailureException& ) { - // This just means the test was aborted due to failure - } - catch(...) { - makeUnexpectedResultBuilder().useActiveException(); - } - handleUnfinishedSections(); - m_messages.clear(); - - Counts assertions = m_totals.assertions - prevAssertions; - bool missingAssertions = testForMissingAssertions( assertions ); - - if( testCaseInfo.okToFail() ) { - std::swap( assertions.failedButOk, assertions.failed ); - m_totals.assertions.failed -= assertions.failedButOk; - m_totals.assertions.failedButOk += assertions.failedButOk; - } - - SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); - m_reporter->sectionEnded( testCaseSectionStats ); - } - - void invokeActiveTestCase() { - FatalConditionHandler fatalConditionHandler; // Handle signals - m_activeTestCase->invoke(); - fatalConditionHandler.reset(); - } - - private: - - ResultBuilder makeUnexpectedResultBuilder() const { - return ResultBuilder( m_lastAssertionInfo.macroName.c_str(), - m_lastAssertionInfo.lineInfo, - m_lastAssertionInfo.capturedExpression.c_str(), - m_lastAssertionInfo.resultDisposition ); - } - - void handleUnfinishedSections() { - // If sections ended prematurely due to an exception we stored their - // infos here so we can tear them down outside the unwind process. - for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), - itEnd = m_unfinishedSections.rend(); - it != itEnd; - ++it ) - sectionEnded( it->info, it->prevAssertions, it->durationInSeconds ); - m_unfinishedSections.clear(); - } - - struct UnfinishedSections { - UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds ) - : info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) - {} - - SectionInfo info; - Counts prevAssertions; - double durationInSeconds; - }; - - TestRunInfo m_runInfo; - IMutableContext& m_context; - TestCase const* m_activeTestCase; - Option m_testCaseTracker; - AssertionResult m_lastResult; - - Ptr m_config; - Totals m_totals; - Ptr m_reporter; - std::vector m_messages; - IRunner* m_prevRunner; - IResultCapture* m_prevResultCapture; - Ptr m_prevConfig; - AssertionInfo m_lastAssertionInfo; - std::vector m_unfinishedSections; - }; - - IResultCapture& getResultCapture() { - if( IResultCapture* capture = getCurrentContext().getResultCapture() ) - return *capture; - else - throw std::logic_error( "No result capture instance" ); - } - -} // end namespace Catch - -// #included from: internal/catch_version.h -#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED - -namespace Catch { - - // Versioning information - struct Version { - Version( unsigned int _majorVersion, - unsigned int _minorVersion, - unsigned int _buildNumber, - char const* const _branchName ) - : majorVersion( _majorVersion ), - minorVersion( _minorVersion ), - buildNumber( _buildNumber ), - branchName( _branchName ) - {} - - unsigned int const majorVersion; - unsigned int const minorVersion; - unsigned int const buildNumber; - char const* const branchName; - - private: - void operator=( Version const& ); - }; - - extern Version libraryVersion; -} - -#include -#include -#include - -namespace Catch { - - class Runner { - - public: - Runner( Ptr const& config ) - : m_config( config ) - { - openStream(); - makeReporter(); - } - - Totals runTests() { - - RunContext context( m_config.get(), m_reporter ); - - Totals totals; - - context.testGroupStarting( "all tests", 1, 1 ); // deprecated? - - TestSpec testSpec = m_config->testSpec(); - if( !testSpec.hasFilters() ) - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests - - std::vector testCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, testCases ); - - int testsRunForGroup = 0; - for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); - it != itEnd; - ++it ) { - testsRunForGroup++; - if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) { - - if( context.aborting() ) - break; - - totals += context.runTest( *it ); - m_testsAlreadyRun.insert( *it ); - } - } - std::vector skippedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, skippedTestCases, true ); - - for( std::vector::const_iterator it = skippedTestCases.begin(), itEnd = skippedTestCases.end(); - it != itEnd; - ++it ) - m_reporter->skipTest( *it ); - - context.testGroupEnded( "all tests", totals, 1, 1 ); - return totals; - } - - private: - void openStream() { - // Open output file, if specified - if( !m_config->getFilename().empty() ) { - m_ofs.open( m_config->getFilename().c_str() ); - if( m_ofs.fail() ) { - std::ostringstream oss; - oss << "Unable to open file: '" << m_config->getFilename() << "'"; - throw std::domain_error( oss.str() ); - } - m_config->setStreamBuf( m_ofs.rdbuf() ); - } - } - void makeReporter() { - std::string reporterName = m_config->getReporterName().empty() - ? "console" - : m_config->getReporterName(); - - m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, m_config.get() ); - if( !m_reporter ) { - std::ostringstream oss; - oss << "No reporter registered with name: '" << reporterName << "'"; - throw std::domain_error( oss.str() ); - } - } - - private: - Ptr m_config; - std::ofstream m_ofs; - Ptr m_reporter; - std::set m_testsAlreadyRun; - }; - - class Session : NonCopyable { - static bool alreadyInstantiated; - - public: - - struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; - - Session() - : m_cli( makeCommandLineParser() ) { - if( alreadyInstantiated ) { - std::string msg = "Only one instance of Catch::Session can ever be used"; - Catch::cerr() << msg << std::endl; - throw std::logic_error( msg ); - } - alreadyInstantiated = true; - } - ~Session() { - Catch::cleanUp(); - } - - void showHelp( std::string const& processName ) { - Catch::cout() << "\nCatch v" << libraryVersion.majorVersion << "." - << libraryVersion.minorVersion << " build " - << libraryVersion.buildNumber; - if( libraryVersion.branchName != std::string( "master" ) ) - Catch::cout() << " (" << libraryVersion.branchName << " branch)"; - Catch::cout() << "\n"; - - m_cli.usage( Catch::cout(), processName ); - Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; - } - - int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { - try { - m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); - m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); - if( m_configData.showHelp ) - showHelp( m_configData.processName ); - m_config.reset(); - } - catch( std::exception& ex ) { - { - Colour colourGuard( Colour::Red ); - Catch::cerr() << "\nError(s) in input:\n" - << Text( ex.what(), TextAttributes().setIndent(2) ) - << "\n\n"; - } - m_cli.usage( Catch::cout(), m_configData.processName ); - return (std::numeric_limits::max)(); - } - return 0; - } - - void useConfigData( ConfigData const& _configData ) { - m_configData = _configData; - m_config.reset(); - } - - int run( int argc, char* const argv[] ) { - - int returnCode = applyCommandLine( argc, argv ); - if( returnCode == 0 ) - returnCode = run(); - return returnCode; - } - - int run() { - if( m_configData.showHelp ) - return 0; - - try - { - config(); // Force config to be constructed - - std::srand( m_configData.rngSeed ); - - Runner runner( m_config ); - - // Handle list request - if( Option listed = list( config() ) ) - return static_cast( *listed ); - - return static_cast( runner.runTests().assertions.failed ); - } - catch( std::exception& ex ) { - Catch::cerr() << ex.what() << std::endl; - return (std::numeric_limits::max)(); - } - } - - Clara::CommandLine const& cli() const { - return m_cli; - } - std::vector const& unusedTokens() const { - return m_unusedTokens; - } - ConfigData& configData() { - return m_configData; - } - Config& config() { - if( !m_config ) - m_config = new Config( m_configData ); - return *m_config; - } - - private: - Clara::CommandLine m_cli; - std::vector m_unusedTokens; - ConfigData m_configData; - Ptr m_config; - }; - - bool Session::alreadyInstantiated = false; - -} // end namespace Catch - -// #included from: catch_registry_hub.hpp -#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED - -// #included from: catch_test_case_registry_impl.hpp -#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED - -#include -#include -#include -#include -#include - -namespace Catch { - - class TestRegistry : public ITestCaseRegistry { - struct LexSort { - bool operator() (TestCase i,TestCase j) const { return (i const& getAllTests() const { - return m_functionsInOrder; - } - - virtual std::vector const& getAllNonHiddenTests() const { - return m_nonHiddenFunctions; - } - - virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const { - - for( std::vector::const_iterator it = m_functionsInOrder.begin(), - itEnd = m_functionsInOrder.end(); - it != itEnd; - ++it ) { - bool includeTest = testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() ); - if( includeTest != negated ) - matchingTestCases.push_back( *it ); - } - sortTests( config, matchingTestCases ); - } - - private: - - static void sortTests( IConfig const& config, std::vector& matchingTestCases ) { - - switch( config.runOrder() ) { - case RunTests::InLexicographicalOrder: - std::sort( matchingTestCases.begin(), matchingTestCases.end(), LexSort() ); - break; - case RunTests::InRandomOrder: - { - RandomNumberGenerator rng; - std::random_shuffle( matchingTestCases.begin(), matchingTestCases.end(), rng ); - } - break; - case RunTests::InDeclarationOrder: - // already in declaration order - break; - } - } - std::set m_functions; - std::vector m_functionsInOrder; - std::vector m_nonHiddenFunctions; - size_t m_unnamedCount; - }; - - /////////////////////////////////////////////////////////////////////////// - - class FreeFunctionTestCase : public SharedImpl { - public: - - FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} - - virtual void invoke() const { - m_fun(); - } - - private: - virtual ~FreeFunctionTestCase(); - - TestFunction m_fun; - }; - - inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { - std::string className = classOrQualifiedMethodName; - if( startsWith( className, "&" ) ) - { - std::size_t lastColons = className.rfind( "::" ); - std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); - if( penultimateColons == std::string::npos ) - penultimateColons = 1; - className = className.substr( penultimateColons, lastColons-penultimateColons ); - } - return className; - } - - /////////////////////////////////////////////////////////////////////////// - - AutoReg::AutoReg( TestFunction function, - SourceLineInfo const& lineInfo, - NameAndDesc const& nameAndDesc ) { - registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); - } - - AutoReg::~AutoReg() {} - - void AutoReg::registerTestCase( ITestCase* testCase, - char const* classOrQualifiedMethodName, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ) { - - getMutableRegistryHub().registerTest - ( makeTestCase( testCase, - extractClassName( classOrQualifiedMethodName ), - nameAndDesc.name, - nameAndDesc.description, - lineInfo ) ); - } - -} // end namespace Catch - -// #included from: catch_reporter_registry.hpp -#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED - -#include - -namespace Catch { - - class ReporterRegistry : public IReporterRegistry { - - public: - - virtual ~ReporterRegistry() { - deleteAllValues( m_factories ); - } - - virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const { - FactoryMap::const_iterator it = m_factories.find( name ); - if( it == m_factories.end() ) - return NULL; - return it->second->create( ReporterConfig( config ) ); - } - - void registerReporter( std::string const& name, IReporterFactory* factory ) { - m_factories.insert( std::make_pair( name, factory ) ); - } - - FactoryMap const& getFactories() const { - return m_factories; - } - - private: - FactoryMap m_factories; - }; -} - -// #included from: catch_exception_translator_registry.hpp -#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED - -#ifdef __OBJC__ -#import "Foundation/Foundation.h" -#endif - -namespace Catch { - - class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { - public: - ~ExceptionTranslatorRegistry() { - deleteAll( m_translators ); - } - - virtual void registerTranslator( const IExceptionTranslator* translator ) { - m_translators.push_back( translator ); - } - - virtual std::string translateActiveException() const { - try { -#ifdef __OBJC__ - // In Objective-C try objective-c exceptions first - @try { - throw; - } - @catch (NSException *exception) { - return Catch::toString( [exception description] ); - } -#else - throw; -#endif - } - catch( TestFailureException& ) { - throw; - } - catch( std::exception& ex ) { - return ex.what(); - } - catch( std::string& msg ) { - return msg; - } - catch( const char* msg ) { - return msg; - } - catch(...) { - return tryTranslators( m_translators.begin() ); - } - } - - std::string tryTranslators( std::vector::const_iterator it ) const { - if( it == m_translators.end() ) - return "Unknown exception"; - - try { - return (*it)->translate(); - } - catch(...) { - return tryTranslators( it+1 ); - } - } - - private: - std::vector m_translators; - }; -} - -namespace Catch { - - namespace { - - class RegistryHub : public IRegistryHub, public IMutableRegistryHub { - - RegistryHub( RegistryHub const& ); - void operator=( RegistryHub const& ); - - public: // IRegistryHub - RegistryHub() { - } - virtual IReporterRegistry const& getReporterRegistry() const { - return m_reporterRegistry; - } - virtual ITestCaseRegistry const& getTestCaseRegistry() const { - return m_testCaseRegistry; - } - virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() { - return m_exceptionTranslatorRegistry; - } - - public: // IMutableRegistryHub - virtual void registerReporter( std::string const& name, IReporterFactory* factory ) { - m_reporterRegistry.registerReporter( name, factory ); - } - virtual void registerTest( TestCase const& testInfo ) { - m_testCaseRegistry.registerTest( testInfo ); - } - virtual void registerTranslator( const IExceptionTranslator* translator ) { - m_exceptionTranslatorRegistry.registerTranslator( translator ); - } - - private: - TestRegistry m_testCaseRegistry; - ReporterRegistry m_reporterRegistry; - ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; - }; - - // Single, global, instance - inline RegistryHub*& getTheRegistryHub() { - static RegistryHub* theRegistryHub = NULL; - if( !theRegistryHub ) - theRegistryHub = new RegistryHub(); - return theRegistryHub; - } - } - - IRegistryHub& getRegistryHub() { - return *getTheRegistryHub(); - } - IMutableRegistryHub& getMutableRegistryHub() { - return *getTheRegistryHub(); - } - void cleanUp() { - delete getTheRegistryHub(); - getTheRegistryHub() = NULL; - cleanUpContext(); - } - std::string translateActiveException() { - return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); - } - -} // end namespace Catch - -// #included from: catch_notimplemented_exception.hpp -#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED - -#include - -namespace Catch { - - NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) - : m_lineInfo( lineInfo ) { - std::ostringstream oss; - oss << lineInfo << ": function "; - oss << "not implemented"; - m_what = oss.str(); - } - - const char* NotImplementedException::what() const CATCH_NOEXCEPT { - return m_what.c_str(); - } - -} // end namespace Catch - -// #included from: catch_context_impl.hpp -#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED - -// #included from: catch_stream.hpp -#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED - -// #included from: catch_streambuf.h -#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED - -#include - -namespace Catch { - - class StreamBufBase : public std::streambuf { - public: - virtual ~StreamBufBase() CATCH_NOEXCEPT; - }; -} - -#include -#include -#include - -namespace Catch { - - template - class StreamBufImpl : public StreamBufBase { - char data[bufferSize]; - WriterF m_writer; - - public: - StreamBufImpl() { - setp( data, data + sizeof(data) ); - } - - ~StreamBufImpl() CATCH_NOEXCEPT { - sync(); - } - - private: - int overflow( int c ) { - sync(); - - if( c != EOF ) { - if( pbase() == epptr() ) - m_writer( std::string( 1, static_cast( c ) ) ); - else - sputc( static_cast( c ) ); - } - return 0; - } - - int sync() { - if( pbase() != pptr() ) { - m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); - setp( pbase(), epptr() ); - } - return 0; - } - }; - - /////////////////////////////////////////////////////////////////////////// - - struct OutputDebugWriter { - - void operator()( std::string const&str ) { - writeToDebugConsole( str ); - } - }; - - Stream::Stream() - : streamBuf( NULL ), isOwned( false ) - {} - - Stream::Stream( std::streambuf* _streamBuf, bool _isOwned ) - : streamBuf( _streamBuf ), isOwned( _isOwned ) - {} - - void Stream::release() { - if( isOwned ) { - delete streamBuf; - streamBuf = NULL; - isOwned = false; - } - } - -#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement this functions - std::ostream& cout() { - return std::cout; - } - std::ostream& cerr() { - return std::cerr; - } -#endif -} - -namespace Catch { - - class Context : public IMutableContext { - - Context() : m_config( NULL ), m_runner( NULL ), m_resultCapture( NULL ) {} - Context( Context const& ); - void operator=( Context const& ); - - public: // IContext - virtual IResultCapture* getResultCapture() { - return m_resultCapture; - } - virtual IRunner* getRunner() { - return m_runner; - } - virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { - return getGeneratorsForCurrentTest() - .getGeneratorInfo( fileInfo, totalSize ) - .getCurrentIndex(); - } - virtual bool advanceGeneratorsForCurrentTest() { - IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); - return generators && generators->moveNext(); - } - - virtual Ptr getConfig() const { - return m_config; - } - - public: // IMutableContext - virtual void setResultCapture( IResultCapture* resultCapture ) { - m_resultCapture = resultCapture; - } - virtual void setRunner( IRunner* runner ) { - m_runner = runner; - } - virtual void setConfig( Ptr const& config ) { - m_config = config; - } - - friend IMutableContext& getCurrentMutableContext(); - - private: - IGeneratorsForTest* findGeneratorsForCurrentTest() { - std::string testName = getResultCapture()->getCurrentTestName(); - - std::map::const_iterator it = - m_generatorsByTestName.find( testName ); - return it != m_generatorsByTestName.end() - ? it->second - : NULL; - } - - IGeneratorsForTest& getGeneratorsForCurrentTest() { - IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); - if( !generators ) { - std::string testName = getResultCapture()->getCurrentTestName(); - generators = createGeneratorsForTest(); - m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); - } - return *generators; - } - - private: - Ptr m_config; - IRunner* m_runner; - IResultCapture* m_resultCapture; - std::map m_generatorsByTestName; - }; - - namespace { - Context* currentContext = NULL; - } - IMutableContext& getCurrentMutableContext() { - if( !currentContext ) - currentContext = new Context(); - return *currentContext; - } - IContext& getCurrentContext() { - return getCurrentMutableContext(); - } - - Stream createStream( std::string const& streamName ) { - if( streamName == "stdout" ) return Stream( Catch::cout().rdbuf(), false ); - if( streamName == "stderr" ) return Stream( Catch::cerr().rdbuf(), false ); - if( streamName == "debug" ) return Stream( new StreamBufImpl, true ); - - throw std::domain_error( "Unknown stream: " + streamName ); - } - - void cleanUpContext() { - delete currentContext; - currentContext = NULL; - } -} - -// #included from: catch_console_colour_impl.hpp -#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED - -namespace Catch { - namespace { - - struct IColourImpl { - virtual ~IColourImpl() {} - virtual void use( Colour::Code _colourCode ) = 0; - }; - - struct NoColourImpl : IColourImpl { - void use( Colour::Code ) {} - - static IColourImpl* instance() { - static NoColourImpl s_instance; - return &s_instance; - } - }; - - } // anon namespace -} // namespace Catch - -#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) -# ifdef CATCH_PLATFORM_WINDOWS -# define CATCH_CONFIG_COLOUR_WINDOWS -# else -# define CATCH_CONFIG_COLOUR_ANSI -# endif -#endif - -#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// - -#ifndef NOMINMAX -#define NOMINMAX -#endif - -#ifdef __AFXDLL -#include -#else -#include -#endif - -namespace Catch { -namespace { - - class Win32ColourImpl : public IColourImpl { - public: - Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) - { - CONSOLE_SCREEN_BUFFER_INFO csbiInfo; - GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); - originalAttributes = csbiInfo.wAttributes; - } - - virtual void use( Colour::Code _colourCode ) { - switch( _colourCode ) { - case Colour::None: return setTextAttribute( originalAttributes ); - case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); - case Colour::Red: return setTextAttribute( FOREGROUND_RED ); - case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); - case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); - case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); - case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); - case Colour::Grey: return setTextAttribute( 0 ); - - case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); - case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); - case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); - case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); - - case Colour::Bright: throw std::logic_error( "not a colour" ); - } - } - - private: - void setTextAttribute( WORD _textAttribute ) { - SetConsoleTextAttribute( stdoutHandle, _textAttribute ); - } - HANDLE stdoutHandle; - WORD originalAttributes; - }; - - IColourImpl* platformColourInstance() { - static Win32ColourImpl s_instance; - return &s_instance; - } - -} // end anon namespace -} // end namespace Catch - -#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// - -#include - -namespace Catch { -namespace { - - // use POSIX/ ANSI console terminal codes - // Thanks to Adam Strzelecki for original contribution - // (http://github.com/nanoant) - // https://github.com/philsquared/Catch/pull/131 - class PosixColourImpl : public IColourImpl { - public: - virtual void use( Colour::Code _colourCode ) { - switch( _colourCode ) { - case Colour::None: - case Colour::White: return setColour( "[0m" ); - case Colour::Red: return setColour( "[0;31m" ); - case Colour::Green: return setColour( "[0;32m" ); - case Colour::Blue: return setColour( "[0:34m" ); - case Colour::Cyan: return setColour( "[0;36m" ); - case Colour::Yellow: return setColour( "[0;33m" ); - case Colour::Grey: return setColour( "[1;30m" ); - - case Colour::LightGrey: return setColour( "[0;37m" ); - case Colour::BrightRed: return setColour( "[1;31m" ); - case Colour::BrightGreen: return setColour( "[1;32m" ); - case Colour::BrightWhite: return setColour( "[1;37m" ); - - case Colour::Bright: throw std::logic_error( "not a colour" ); - } - } - static IColourImpl* instance() { - static PosixColourImpl s_instance; - return &s_instance; - } - - private: - void setColour( const char* _escapeCode ) { - Catch::cout() << '\033' << _escapeCode; - } - }; - - IColourImpl* platformColourInstance() { - return isatty(STDOUT_FILENO) - ? PosixColourImpl::instance() - : NoColourImpl::instance(); - } - -} // end anon namespace -} // end namespace Catch - -#else // not Windows or ANSI /////////////////////////////////////////////// - -namespace Catch { - - static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } - -} // end namespace Catch - -#endif // Windows/ ANSI/ None - -namespace Catch { - - Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } - Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast( _other ).m_moved = true; } - Colour::~Colour(){ if( !m_moved ) use( None ); } - - void Colour::use( Code _colourCode ) { - static IColourImpl* impl = isDebuggerActive() - ? NoColourImpl::instance() - : platformColourInstance(); - impl->use( _colourCode ); - } - -} // end namespace Catch - -// #included from: catch_generators_impl.hpp -#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED - -#include -#include -#include - -namespace Catch { - - struct GeneratorInfo : IGeneratorInfo { - - GeneratorInfo( std::size_t size ) - : m_size( size ), - m_currentIndex( 0 ) - {} - - bool moveNext() { - if( ++m_currentIndex == m_size ) { - m_currentIndex = 0; - return false; - } - return true; - } - - std::size_t getCurrentIndex() const { - return m_currentIndex; - } - - std::size_t m_size; - std::size_t m_currentIndex; - }; - - /////////////////////////////////////////////////////////////////////////// - - class GeneratorsForTest : public IGeneratorsForTest { - - public: - ~GeneratorsForTest() { - deleteAll( m_generatorsInOrder ); - } - - IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { - std::map::const_iterator it = m_generatorsByName.find( fileInfo ); - if( it == m_generatorsByName.end() ) { - IGeneratorInfo* info = new GeneratorInfo( size ); - m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); - m_generatorsInOrder.push_back( info ); - return *info; - } - return *it->second; - } - - bool moveNext() { - std::vector::const_iterator it = m_generatorsInOrder.begin(); - std::vector::const_iterator itEnd = m_generatorsInOrder.end(); - for(; it != itEnd; ++it ) { - if( (*it)->moveNext() ) - return true; - } - return false; - } - - private: - std::map m_generatorsByName; - std::vector m_generatorsInOrder; - }; - - IGeneratorsForTest* createGeneratorsForTest() - { - return new GeneratorsForTest(); - } - -} // end namespace Catch - -// #included from: catch_assertionresult.hpp -#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED - -namespace Catch { - - AssertionInfo::AssertionInfo( std::string const& _macroName, - SourceLineInfo const& _lineInfo, - std::string const& _capturedExpression, - ResultDisposition::Flags _resultDisposition ) - : macroName( _macroName ), - lineInfo( _lineInfo ), - capturedExpression( _capturedExpression ), - resultDisposition( _resultDisposition ) - {} - - AssertionResult::AssertionResult() {} - - AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) - : m_info( info ), - m_resultData( data ) - {} - - AssertionResult::~AssertionResult() {} - - // Result was a success - bool AssertionResult::succeeded() const { - return Catch::isOk( m_resultData.resultType ); - } - - // Result was a success, or failure is suppressed - bool AssertionResult::isOk() const { - return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); - } - - ResultWas::OfType AssertionResult::getResultType() const { - return m_resultData.resultType; - } - - bool AssertionResult::hasExpression() const { - return !m_info.capturedExpression.empty(); - } - - bool AssertionResult::hasMessage() const { - return !m_resultData.message.empty(); - } - - std::string AssertionResult::getExpression() const { - if( isFalseTest( m_info.resultDisposition ) ) - return "!" + m_info.capturedExpression; - else - return m_info.capturedExpression; - } - std::string AssertionResult::getExpressionInMacro() const { - if( m_info.macroName.empty() ) - return m_info.capturedExpression; - else - return m_info.macroName + "( " + m_info.capturedExpression + " )"; - } - - bool AssertionResult::hasExpandedExpression() const { - return hasExpression() && getExpandedExpression() != getExpression(); - } - - std::string AssertionResult::getExpandedExpression() const { - return m_resultData.reconstructedExpression; - } - - std::string AssertionResult::getMessage() const { - return m_resultData.message; - } - SourceLineInfo AssertionResult::getSourceInfo() const { - return m_info.lineInfo; - } - - std::string AssertionResult::getTestMacroName() const { - return m_info.macroName; - } - -} // end namespace Catch - -// #included from: catch_test_case_info.hpp -#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED - -namespace Catch { - - inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { - if( startsWith( tag, "." ) || - tag == "hide" || - tag == "!hide" ) - return TestCaseInfo::IsHidden; - else if( tag == "!throws" ) - return TestCaseInfo::Throws; - else if( tag == "!shouldfail" ) - return TestCaseInfo::ShouldFail; - else if( tag == "!mayfail" ) - return TestCaseInfo::MayFail; - else - return TestCaseInfo::None; - } - inline bool isReservedTag( std::string const& tag ) { - return TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] ); - } - inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { - if( isReservedTag( tag ) ) { - { - Colour colourGuard( Colour::Red ); - Catch::cerr() - << "Tag name [" << tag << "] not allowed.\n" - << "Tag names starting with non alpha-numeric characters are reserved\n"; - } - { - Colour colourGuard( Colour::FileName ); - Catch::cerr() << _lineInfo << std::endl; - } - exit(1); - } - } - - TestCase makeTestCase( ITestCase* _testCase, - std::string const& _className, - std::string const& _name, - std::string const& _descOrTags, - SourceLineInfo const& _lineInfo ) - { - bool isHidden( startsWith( _name, "./" ) ); // Legacy support - - // Parse out tags - std::set tags; - std::string desc, tag; - bool inTag = false; - for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { - char c = _descOrTags[i]; - if( !inTag ) { - if( c == '[' ) - inTag = true; - else - desc += c; - } - else { - if( c == ']' ) { - TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); - if( prop == TestCaseInfo::IsHidden ) - isHidden = true; - else if( prop == TestCaseInfo::None ) - enforceNotReservedTag( tag, _lineInfo ); - - tags.insert( tag ); - tag.clear(); - inTag = false; - } - else - tag += c; - } - } - if( isHidden ) { - tags.insert( "hide" ); - tags.insert( "." ); - } - - TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); - return TestCase( _testCase, info ); - } - - TestCaseInfo::TestCaseInfo( std::string const& _name, - std::string const& _className, - std::string const& _description, - std::set const& _tags, - SourceLineInfo const& _lineInfo ) - : name( _name ), - className( _className ), - description( _description ), - tags( _tags ), - lineInfo( _lineInfo ), - properties( None ) - { - std::ostringstream oss; - for( std::set::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) { - oss << "[" << *it << "]"; - std::string lcaseTag = toLower( *it ); - properties = static_cast( properties | parseSpecialTag( lcaseTag ) ); - lcaseTags.insert( lcaseTag ); - } - tagsAsString = oss.str(); - } - - TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) - : name( other.name ), - className( other.className ), - description( other.description ), - tags( other.tags ), - lcaseTags( other.lcaseTags ), - tagsAsString( other.tagsAsString ), - lineInfo( other.lineInfo ), - properties( other.properties ) - {} - - bool TestCaseInfo::isHidden() const { - return ( properties & IsHidden ) != 0; - } - bool TestCaseInfo::throws() const { - return ( properties & Throws ) != 0; - } - bool TestCaseInfo::okToFail() const { - return ( properties & (ShouldFail | MayFail ) ) != 0; - } - bool TestCaseInfo::expectedToFail() const { - return ( properties & (ShouldFail ) ) != 0; - } - - TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} - - TestCase::TestCase( TestCase const& other ) - : TestCaseInfo( other ), - test( other.test ) - {} - - TestCase TestCase::withName( std::string const& _newName ) const { - TestCase other( *this ); - other.name = _newName; - return other; - } - - void TestCase::swap( TestCase& other ) { - test.swap( other.test ); - name.swap( other.name ); - className.swap( other.className ); - description.swap( other.description ); - tags.swap( other.tags ); - lcaseTags.swap( other.lcaseTags ); - tagsAsString.swap( other.tagsAsString ); - std::swap( TestCaseInfo::properties, static_cast( other ).properties ); - std::swap( lineInfo, other.lineInfo ); - } - - void TestCase::invoke() const { - test->invoke(); - } - - bool TestCase::operator == ( TestCase const& other ) const { - return test.get() == other.test.get() && - name == other.name && - className == other.className; - } - - bool TestCase::operator < ( TestCase const& other ) const { - return name < other.name; - } - TestCase& TestCase::operator = ( TestCase const& other ) { - TestCase temp( other ); - swap( temp ); - return *this; - } - - TestCaseInfo const& TestCase::getTestCaseInfo() const - { - return *this; - } - -} // end namespace Catch - -// #included from: catch_version.hpp -#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED - -namespace Catch { - - // These numbers are maintained by a script - Version libraryVersion( 1, 1, 13, "develop" ); -} - -// #included from: catch_message.hpp -#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED - -namespace Catch { - - MessageInfo::MessageInfo( std::string const& _macroName, - SourceLineInfo const& _lineInfo, - ResultWas::OfType _type ) - : macroName( _macroName ), - lineInfo( _lineInfo ), - type( _type ), - sequence( ++globalCount ) - {} - - // This may need protecting if threading support is added - unsigned int MessageInfo::globalCount = 0; - - //////////////////////////////////////////////////////////////////////////// - - ScopedMessage::ScopedMessage( MessageBuilder const& builder ) - : m_info( builder.m_info ) - { - m_info.message = builder.m_stream.str(); - getResultCapture().pushScopedMessage( m_info ); - } - ScopedMessage::ScopedMessage( ScopedMessage const& other ) - : m_info( other.m_info ) - {} - - ScopedMessage::~ScopedMessage() { - getResultCapture().popScopedMessage( m_info ); - } - -} // end namespace Catch - -// #included from: catch_legacy_reporter_adapter.hpp -#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED - -// #included from: catch_legacy_reporter_adapter.h -#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED - -namespace Catch -{ - // Deprecated - struct IReporter : IShared { - virtual ~IReporter(); - - virtual bool shouldRedirectStdout() const = 0; - - virtual void StartTesting() = 0; - virtual void EndTesting( Totals const& totals ) = 0; - virtual void StartGroup( std::string const& groupName ) = 0; - virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; - virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; - virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; - virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; - virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; - virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; - virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; - virtual void Aborted() = 0; - virtual void Result( AssertionResult const& result ) = 0; - }; - - class LegacyReporterAdapter : public SharedImpl - { - public: - LegacyReporterAdapter( Ptr const& legacyReporter ); - virtual ~LegacyReporterAdapter(); - - virtual ReporterPreferences getPreferences() const; - virtual void noMatchingTestCases( std::string const& ); - virtual void testRunStarting( TestRunInfo const& ); - virtual void testGroupStarting( GroupInfo const& groupInfo ); - virtual void testCaseStarting( TestCaseInfo const& testInfo ); - virtual void sectionStarting( SectionInfo const& sectionInfo ); - virtual void assertionStarting( AssertionInfo const& ); - virtual bool assertionEnded( AssertionStats const& assertionStats ); - virtual void sectionEnded( SectionStats const& sectionStats ); - virtual void testCaseEnded( TestCaseStats const& testCaseStats ); - virtual void testGroupEnded( TestGroupStats const& testGroupStats ); - virtual void testRunEnded( TestRunStats const& testRunStats ); - virtual void skipTest( TestCaseInfo const& ); - - private: - Ptr m_legacyReporter; - }; -} - -namespace Catch -{ - LegacyReporterAdapter::LegacyReporterAdapter( Ptr const& legacyReporter ) - : m_legacyReporter( legacyReporter ) - {} - LegacyReporterAdapter::~LegacyReporterAdapter() {} - - ReporterPreferences LegacyReporterAdapter::getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); - return prefs; - } - - void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} - void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { - m_legacyReporter->StartTesting(); - } - void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { - m_legacyReporter->StartGroup( groupInfo.name ); - } - void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { - m_legacyReporter->StartTestCase( testInfo ); - } - void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { - m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); - } - void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { - // Not on legacy interface - } - - bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { - if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { - for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); - it != itEnd; - ++it ) { - if( it->type == ResultWas::Info ) { - ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); - rb << it->message; - rb.setResultType( ResultWas::Info ); - AssertionResult result = rb.build(); - m_legacyReporter->Result( result ); - } - } - } - m_legacyReporter->Result( assertionStats.assertionResult ); - return true; - } - void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { - if( sectionStats.missingAssertions ) - m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); - m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); - } - void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { - m_legacyReporter->EndTestCase - ( testCaseStats.testInfo, - testCaseStats.totals, - testCaseStats.stdOut, - testCaseStats.stdErr ); - } - void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { - if( testGroupStats.aborting ) - m_legacyReporter->Aborted(); - m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); - } - void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { - m_legacyReporter->EndTesting( testRunStats.totals ); - } - void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { - } -} - -// #included from: catch_timer.hpp - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wc++11-long-long" -#endif - -#ifdef CATCH_PLATFORM_WINDOWS -#include -#else -#include -#endif - -namespace Catch { - - namespace { -#ifdef CATCH_PLATFORM_WINDOWS - uint64_t getCurrentTicks() { - static uint64_t hz=0, hzo=0; - if (!hz) { - QueryPerformanceFrequency((LARGE_INTEGER*)&hz); - QueryPerformanceCounter((LARGE_INTEGER*)&hzo); - } - uint64_t t; - QueryPerformanceCounter((LARGE_INTEGER*)&t); - return ((t-hzo)*1000000)/hz; - } -#else - uint64_t getCurrentTicks() { - timeval t; - gettimeofday(&t,NULL); - return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); - } -#endif - } - - void Timer::start() { - m_ticks = getCurrentTicks(); - } - unsigned int Timer::getElapsedMicroseconds() const { - return static_cast(getCurrentTicks() - m_ticks); - } - unsigned int Timer::getElapsedMilliseconds() const { - return static_cast(getElapsedMicroseconds()/1000); - } - double Timer::getElapsedSeconds() const { - return getElapsedMicroseconds()/1000000.0; - } - -} // namespace Catch - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif -// #included from: catch_common.hpp -#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED - -namespace Catch { - - bool startsWith( std::string const& s, std::string const& prefix ) { - return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix; - } - bool endsWith( std::string const& s, std::string const& suffix ) { - return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix; - } - bool contains( std::string const& s, std::string const& infix ) { - return s.find( infix ) != std::string::npos; - } - void toLowerInPlace( std::string& s ) { - std::transform( s.begin(), s.end(), s.begin(), ::tolower ); - } - std::string toLower( std::string const& s ) { - std::string lc = s; - toLowerInPlace( lc ); - return lc; - } - std::string trim( std::string const& str ) { - static char const* whitespaceChars = "\n\r\t "; - std::string::size_type start = str.find_first_not_of( whitespaceChars ); - std::string::size_type end = str.find_last_not_of( whitespaceChars ); - - return start != std::string::npos ? str.substr( start, 1+end-start ) : ""; - } - - bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { - bool replaced = false; - std::size_t i = str.find( replaceThis ); - while( i != std::string::npos ) { - replaced = true; - str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); - if( i < str.size()-withThis.size() ) - i = str.find( replaceThis, i+withThis.size() ); - else - i = std::string::npos; - } - return replaced; - } - - pluralise::pluralise( std::size_t count, std::string const& label ) - : m_count( count ), - m_label( label ) - {} - - std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { - os << pluraliser.m_count << " " << pluraliser.m_label; - if( pluraliser.m_count != 1 ) - os << "s"; - return os; - } - - SourceLineInfo::SourceLineInfo() : line( 0 ){} - SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) - : file( _file ), - line( _line ) - {} - SourceLineInfo::SourceLineInfo( SourceLineInfo const& other ) - : file( other.file ), - line( other.line ) - {} - bool SourceLineInfo::empty() const { - return file.empty(); - } - bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { - return line == other.line && file == other.file; - } - - std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { -#ifndef __GNUG__ - os << info.file << "(" << info.line << ")"; -#else - os << info.file << ":" << info.line; -#endif - return os; - } - - void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { - std::ostringstream oss; - oss << locationInfo << ": Internal Catch error: '" << message << "'"; - if( alwaysTrue() ) - throw std::logic_error( oss.str() ); - } -} - -// #included from: catch_section.hpp -#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED - -namespace Catch { - - SectionInfo::SectionInfo - ( SourceLineInfo const& _lineInfo, - std::string const& _name, - std::string const& _description ) - : name( _name ), - description( _description ), - lineInfo( _lineInfo ) - {} - - Section::Section( SectionInfo const& info ) - : m_info( info ), - m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) - { - m_timer.start(); - } - - Section::~Section() { - if( m_sectionIncluded ) - getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() ); - } - - // This indicates whether the section should be executed or not - Section::operator bool() const { - return m_sectionIncluded; - } - -} // end namespace Catch - -// #included from: catch_debugger.hpp -#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED - -#include - -#ifdef CATCH_PLATFORM_MAC - - #include - #include - #include - #include - #include - - namespace Catch{ - - // The following function is taken directly from the following technical note: - // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html - - // Returns true if the current process is being debugged (either - // running under the debugger or has a debugger attached post facto). - bool isDebuggerActive(){ - - int mib[4]; - struct kinfo_proc info; - size_t size; - - // Initialize the flags so that, if sysctl fails for some bizarre - // reason, we get a predictable result. - - info.kp_proc.p_flag = 0; - - // Initialize mib, which tells sysctl the info we want, in this case - // we're looking for information about a specific process ID. - - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PID; - mib[3] = getpid(); - - // Call sysctl. - - size = sizeof(info); - if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0) != 0 ) { - Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; - return false; - } - - // We're being debugged if the P_TRACED flag is set. - - return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); - } - } // namespace Catch - -#elif defined(_MSC_VER) - extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); - namespace Catch { - bool isDebuggerActive() { - return IsDebuggerPresent() != 0; - } - } -#elif defined(__MINGW32__) - extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); - namespace Catch { - bool isDebuggerActive() { - return IsDebuggerPresent() != 0; - } - } -#else - namespace Catch { - inline bool isDebuggerActive() { return false; } - } -#endif // Platform - -#ifdef CATCH_PLATFORM_WINDOWS - extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* ); - namespace Catch { - void writeToDebugConsole( std::string const& text ) { - ::OutputDebugStringA( text.c_str() ); - } - } -#else - namespace Catch { - void writeToDebugConsole( std::string const& text ) { - // !TBD: Need a version for Mac/ XCode and other IDEs - Catch::cout() << text; - } - } -#endif // Platform - -// #included from: catch_tostring.hpp -#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED - -namespace Catch { - -namespace Detail { - - std::string unprintableString = "{?}"; - - namespace { - struct Endianness { - enum Arch { Big, Little }; - - static Arch which() { - union _{ - int asInt; - char asChar[sizeof (int)]; - } u; - - u.asInt = 1; - return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; - } - }; - } - - std::string rawMemoryToString( const void *object, std::size_t size ) - { - // Reverse order for little endian architectures - int i = 0, end = static_cast( size ), inc = 1; - if( Endianness::which() == Endianness::Little ) { - i = end-1; - end = inc = -1; - } - - unsigned char const *bytes = static_cast(object); - std::ostringstream os; - os << "0x" << std::setfill('0') << std::hex; - for( ; i != end; i += inc ) - os << std::setw(2) << static_cast(bytes[i]); - return os.str(); - } -} - -std::string toString( std::string const& value ) { - std::string s = value; - if( getCurrentContext().getConfig()->showInvisibles() ) { - for(size_t i = 0; i < s.size(); ++i ) { - std::string subs; - switch( s[i] ) { - case '\n': subs = "\\n"; break; - case '\t': subs = "\\t"; break; - default: break; - } - if( !subs.empty() ) { - s = s.substr( 0, i ) + subs + s.substr( i+1 ); - ++i; - } - } - } - return "\"" + s + "\""; -} -std::string toString( std::wstring const& value ) { - - std::string s; - s.reserve( value.size() ); - for(size_t i = 0; i < value.size(); ++i ) - s += value[i] <= 0xff ? static_cast( value[i] ) : '?'; - return Catch::toString( s ); -} - -std::string toString( const char* const value ) { - return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); -} - -std::string toString( char* const value ) { - return Catch::toString( static_cast( value ) ); -} - -std::string toString( const wchar_t* const value ) -{ - return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); -} - -std::string toString( wchar_t* const value ) -{ - return Catch::toString( static_cast( value ) ); -} - -std::string toString( int value ) { - std::ostringstream oss; - if( value > 8192 ) - oss << "0x" << std::hex << value; - else - oss << value; - return oss.str(); -} - -std::string toString( unsigned long value ) { - std::ostringstream oss; - if( value > 8192 ) - oss << "0x" << std::hex << value; - else - oss << value; - return oss.str(); -} - -std::string toString( unsigned int value ) { - return Catch::toString( static_cast( value ) ); -} - -template -std::string fpToString( T value, int precision ) { - std::ostringstream oss; - oss << std::setprecision( precision ) - << std::fixed - << value; - std::string d = oss.str(); - std::size_t i = d.find_last_not_of( '0' ); - if( i != std::string::npos && i != d.size()-1 ) { - if( d[i] == '.' ) - i++; - d = d.substr( 0, i+1 ); - } - return d; -} - -std::string toString( const double value ) { - return fpToString( value, 10 ); -} -std::string toString( const float value ) { - return fpToString( value, 5 ) + "f"; -} - -std::string toString( bool value ) { - return value ? "true" : "false"; -} - -std::string toString( char value ) { - return value < ' ' - ? toString( static_cast( value ) ) - : Detail::makeString( value ); -} - -std::string toString( signed char value ) { - return toString( static_cast( value ) ); -} - -std::string toString( unsigned char value ) { - return toString( static_cast( value ) ); -} - -#ifdef CATCH_CONFIG_CPP11_NULLPTR -std::string toString( std::nullptr_t ) { - return "nullptr"; -} -#endif - -#ifdef __OBJC__ - std::string toString( NSString const * const& nsstring ) { - if( !nsstring ) - return "nil"; - return "@" + toString([nsstring UTF8String]); - } - std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) { - if( !nsstring ) - return "nil"; - return "@" + toString([nsstring UTF8String]); - } - std::string toString( NSObject* const& nsObject ) { - return toString( [nsObject description] ); - } -#endif - -} // end namespace Catch - -// #included from: catch_result_builder.hpp -#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED - -namespace Catch { - - ResultBuilder::ResultBuilder( char const* macroName, - SourceLineInfo const& lineInfo, - char const* capturedExpression, - ResultDisposition::Flags resultDisposition ) - : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition ), - m_shouldDebugBreak( false ), - m_shouldThrow( false ) - {} - - ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { - m_data.resultType = result; - return *this; - } - ResultBuilder& ResultBuilder::setResultType( bool result ) { - m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; - return *this; - } - ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) { - m_exprComponents.lhs = lhs; - return *this; - } - ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) { - m_exprComponents.rhs = rhs; - return *this; - } - ResultBuilder& ResultBuilder::setOp( std::string const& op ) { - m_exprComponents.op = op; - return *this; - } - - void ResultBuilder::endExpression() { - m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition ); - captureExpression(); - } - - void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { - m_assertionInfo.resultDisposition = resultDisposition; - m_stream.oss << Catch::translateActiveException(); - captureResult( ResultWas::ThrewException ); - } - - void ResultBuilder::captureResult( ResultWas::OfType resultType ) { - setResultType( resultType ); - captureExpression(); - } - - void ResultBuilder::captureExpression() { - AssertionResult result = build(); - getResultCapture().assertionEnded( result ); - - if( !result.isOk() ) { - if( getCurrentContext().getConfig()->shouldDebugBreak() ) - m_shouldDebugBreak = true; - if( getCurrentContext().getRunner()->aborting() || m_assertionInfo.resultDisposition == ResultDisposition::Normal ) - m_shouldThrow = true; - } - } - void ResultBuilder::react() { - if( m_shouldThrow ) - throw Catch::TestFailureException(); - } - - bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } - bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } - - AssertionResult ResultBuilder::build() const - { - assert( m_data.resultType != ResultWas::Unknown ); - - AssertionResultData data = m_data; - - // Flip bool results if testFalse is set - if( m_exprComponents.testFalse ) { - if( data.resultType == ResultWas::Ok ) - data.resultType = ResultWas::ExpressionFailed; - else if( data.resultType == ResultWas::ExpressionFailed ) - data.resultType = ResultWas::Ok; - } - - data.message = m_stream.oss.str(); - data.reconstructedExpression = reconstructExpression(); - if( m_exprComponents.testFalse ) { - if( m_exprComponents.op == "" ) - data.reconstructedExpression = "!" + data.reconstructedExpression; - else - data.reconstructedExpression = "!(" + data.reconstructedExpression + ")"; - } - return AssertionResult( m_assertionInfo, data ); - } - std::string ResultBuilder::reconstructExpression() const { - if( m_exprComponents.op == "" ) - return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs; - else if( m_exprComponents.op == "matches" ) - return m_exprComponents.lhs + " " + m_exprComponents.rhs; - else if( m_exprComponents.op != "!" ) { - if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 && - m_exprComponents.lhs.find("\n") == std::string::npos && - m_exprComponents.rhs.find("\n") == std::string::npos ) - return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs; - else - return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs; - } - else - return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}"; - } - -} // end namespace Catch - -// #included from: catch_tag_alias_registry.hpp -#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED - -// #included from: catch_tag_alias_registry.h -#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED - -#include - -namespace Catch { - - class TagAliasRegistry : public ITagAliasRegistry { - public: - virtual ~TagAliasRegistry(); - virtual Option find( std::string const& alias ) const; - virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; - void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); - static TagAliasRegistry& get(); - - private: - std::map m_registry; - }; - -} // end namespace Catch - -#include -#include - -namespace Catch { - - TagAliasRegistry::~TagAliasRegistry() {} - - Option TagAliasRegistry::find( std::string const& alias ) const { - std::map::const_iterator it = m_registry.find( alias ); - if( it != m_registry.end() ) - return it->second; - else - return Option(); - } - - std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { - std::string expandedTestSpec = unexpandedTestSpec; - for( std::map::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); - it != itEnd; - ++it ) { - std::size_t pos = expandedTestSpec.find( it->first ); - if( pos != std::string::npos ) { - expandedTestSpec = expandedTestSpec.substr( 0, pos ) + - it->second.tag + - expandedTestSpec.substr( pos + it->first.size() ); - } - } - return expandedTestSpec; - } - - void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { - - if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) { - std::ostringstream oss; - oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo; - throw std::domain_error( oss.str().c_str() ); - } - if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { - std::ostringstream oss; - oss << "error: tag alias, \"" << alias << "\" already registered.\n" - << "\tFirst seen at " << find(alias)->lineInfo << "\n" - << "\tRedefined at " << lineInfo; - throw std::domain_error( oss.str().c_str() ); - } - } - - TagAliasRegistry& TagAliasRegistry::get() { - static TagAliasRegistry instance; - return instance; - - } - - ITagAliasRegistry::~ITagAliasRegistry() {} - ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); } - - RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { - try { - TagAliasRegistry::get().add( alias, tag, lineInfo ); - } - catch( std::exception& ex ) { - Colour colourGuard( Colour::Red ); - Catch::cerr() << ex.what() << std::endl; - exit(1); - } - } - -} // end namespace Catch - -// #included from: ../reporters/catch_reporter_xml.hpp -#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED - -// #included from: catch_reporter_bases.hpp -#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED - -#include - -namespace Catch { - - struct StreamingReporterBase : SharedImpl { - - StreamingReporterBase( ReporterConfig const& _config ) - : m_config( _config.fullConfig() ), - stream( _config.stream() ) - {} - - virtual ~StreamingReporterBase(); - - virtual void noMatchingTestCases( std::string const& ) {} - - virtual void testRunStarting( TestRunInfo const& _testRunInfo ) { - currentTestRunInfo = _testRunInfo; - } - virtual void testGroupStarting( GroupInfo const& _groupInfo ) { - currentGroupInfo = _groupInfo; - } - - virtual void testCaseStarting( TestCaseInfo const& _testInfo ) { - currentTestCaseInfo = _testInfo; - } - virtual void sectionStarting( SectionInfo const& _sectionInfo ) { - m_sectionStack.push_back( _sectionInfo ); - } - - virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) { - m_sectionStack.pop_back(); - } - virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) { - currentTestCaseInfo.reset(); - assert( m_sectionStack.empty() ); - } - virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) { - currentGroupInfo.reset(); - } - virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) { - currentTestCaseInfo.reset(); - currentGroupInfo.reset(); - currentTestRunInfo.reset(); - } - - virtual void skipTest( TestCaseInfo const& ) { - // Don't do anything with this by default. - // It can optionally be overridden in the derived class. - } - - Ptr m_config; - std::ostream& stream; - - LazyStat currentTestRunInfo; - LazyStat currentGroupInfo; - LazyStat currentTestCaseInfo; - - std::vector m_sectionStack; - }; - - struct CumulativeReporterBase : SharedImpl { - template - struct Node : SharedImpl<> { - explicit Node( T const& _value ) : value( _value ) {} - virtual ~Node() {} - - typedef std::vector > ChildNodes; - T value; - ChildNodes children; - }; - struct SectionNode : SharedImpl<> { - explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} - virtual ~SectionNode(); - - bool operator == ( SectionNode const& other ) const { - return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; - } - bool operator == ( Ptr const& other ) const { - return operator==( *other ); - } - - SectionStats stats; - typedef std::vector > ChildSections; - typedef std::vector Assertions; - ChildSections childSections; - Assertions assertions; - std::string stdOut; - std::string stdErr; - }; - - struct BySectionInfo { - BySectionInfo( SectionInfo const& other ) : m_other( other ) {} - BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} - bool operator() ( Ptr const& node ) const { - return node->stats.sectionInfo.lineInfo == m_other.lineInfo; - } - private: - void operator=( BySectionInfo const& ); - SectionInfo const& m_other; - }; - - typedef Node TestCaseNode; - typedef Node TestGroupNode; - typedef Node TestRunNode; - - CumulativeReporterBase( ReporterConfig const& _config ) - : m_config( _config.fullConfig() ), - stream( _config.stream() ) - {} - ~CumulativeReporterBase(); - - virtual void testRunStarting( TestRunInfo const& ) {} - virtual void testGroupStarting( GroupInfo const& ) {} - - virtual void testCaseStarting( TestCaseInfo const& ) {} - - virtual void sectionStarting( SectionInfo const& sectionInfo ) { - SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); - Ptr node; - if( m_sectionStack.empty() ) { - if( !m_rootSection ) - m_rootSection = new SectionNode( incompleteStats ); - node = m_rootSection; - } - else { - SectionNode& parentNode = *m_sectionStack.back(); - SectionNode::ChildSections::const_iterator it = - std::find_if( parentNode.childSections.begin(), - parentNode.childSections.end(), - BySectionInfo( sectionInfo ) ); - if( it == parentNode.childSections.end() ) { - node = new SectionNode( incompleteStats ); - parentNode.childSections.push_back( node ); - } - else - node = *it; - } - m_sectionStack.push_back( node ); - m_deepestSection = node; - } - - virtual void assertionStarting( AssertionInfo const& ) {} - - virtual bool assertionEnded( AssertionStats const& assertionStats ) { - assert( !m_sectionStack.empty() ); - SectionNode& sectionNode = *m_sectionStack.back(); - sectionNode.assertions.push_back( assertionStats ); - return true; - } - virtual void sectionEnded( SectionStats const& sectionStats ) { - assert( !m_sectionStack.empty() ); - SectionNode& node = *m_sectionStack.back(); - node.stats = sectionStats; - m_sectionStack.pop_back(); - } - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { - Ptr node = new TestCaseNode( testCaseStats ); - assert( m_sectionStack.size() == 0 ); - node->children.push_back( m_rootSection ); - m_testCases.push_back( node ); - m_rootSection.reset(); - - assert( m_deepestSection ); - m_deepestSection->stdOut = testCaseStats.stdOut; - m_deepestSection->stdErr = testCaseStats.stdErr; - } - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { - Ptr node = new TestGroupNode( testGroupStats ); - node->children.swap( m_testCases ); - m_testGroups.push_back( node ); - } - virtual void testRunEnded( TestRunStats const& testRunStats ) { - Ptr node = new TestRunNode( testRunStats ); - node->children.swap( m_testGroups ); - m_testRuns.push_back( node ); - testRunEndedCumulative(); - } - virtual void testRunEndedCumulative() = 0; - - virtual void skipTest( TestCaseInfo const& ) {} - - Ptr m_config; - std::ostream& stream; - std::vector m_assertions; - std::vector > > m_sections; - std::vector > m_testCases; - std::vector > m_testGroups; - - std::vector > m_testRuns; - - Ptr m_rootSection; - Ptr m_deepestSection; - std::vector > m_sectionStack; - - }; - - template - char const* getLineOfChars() { - static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; - if( !*line ) { - memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); - line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; - } - return line; - } - -} // end namespace Catch - -// #included from: ../internal/catch_reporter_registrars.hpp -#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED - -namespace Catch { - - template - class LegacyReporterRegistrar { - - class ReporterFactory : public IReporterFactory { - virtual IStreamingReporter* create( ReporterConfig const& config ) const { - return new LegacyReporterAdapter( new T( config ) ); - } - - virtual std::string getDescription() const { - return T::getDescription(); - } - }; - - public: - - LegacyReporterRegistrar( std::string const& name ) { - getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); - } - }; - - template - class ReporterRegistrar { - - class ReporterFactory : public IReporterFactory { - - // *** Please Note ***: - // - If you end up here looking at a compiler error because it's trying to register - // your custom reporter class be aware that the native reporter interface has changed - // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via - // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. - // However please consider updating to the new interface as the old one is now - // deprecated and will probably be removed quite soon! - // Please contact me via github if you have any questions at all about this. - // In fact, ideally, please contact me anyway to let me know you've hit this - as I have - // no idea who is actually using custom reporters at all (possibly no-one!). - // The new interface is designed to minimise exposure to interface changes in the future. - virtual IStreamingReporter* create( ReporterConfig const& config ) const { - return new T( config ); - } - - virtual std::string getDescription() const { - return T::getDescription(); - } - }; - - public: - - ReporterRegistrar( std::string const& name ) { - getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); - } - }; -} - -#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ - namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } -#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ - namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } - -// #included from: ../internal/catch_xmlwriter.hpp -#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED - -#include -#include -#include - -namespace Catch { - - class XmlWriter { - public: - - class ScopedElement { - public: - ScopedElement( XmlWriter* writer ) - : m_writer( writer ) - {} - - ScopedElement( ScopedElement const& other ) - : m_writer( other.m_writer ){ - other.m_writer = NULL; - } - - ~ScopedElement() { - if( m_writer ) - m_writer->endElement(); - } - - ScopedElement& writeText( std::string const& text, bool indent = true ) { - m_writer->writeText( text, indent ); - return *this; - } - - template - ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { - m_writer->writeAttribute( name, attribute ); - return *this; - } - - private: - mutable XmlWriter* m_writer; - }; - - XmlWriter() - : m_tagIsOpen( false ), - m_needsNewline( false ), - m_os( &Catch::cout() ) - {} - - XmlWriter( std::ostream& os ) - : m_tagIsOpen( false ), - m_needsNewline( false ), - m_os( &os ) - {} - - ~XmlWriter() { - while( !m_tags.empty() ) - endElement(); - } - -//# ifndef CATCH_CPP11_OR_GREATER -// XmlWriter& operator = ( XmlWriter const& other ) { -// XmlWriter temp( other ); -// swap( temp ); -// return *this; -// } -//# else -// XmlWriter( XmlWriter const& ) = default; -// XmlWriter( XmlWriter && ) = default; -// XmlWriter& operator = ( XmlWriter const& ) = default; -// XmlWriter& operator = ( XmlWriter && ) = default; -//# endif -// -// void swap( XmlWriter& other ) { -// std::swap( m_tagIsOpen, other.m_tagIsOpen ); -// std::swap( m_needsNewline, other.m_needsNewline ); -// std::swap( m_tags, other.m_tags ); -// std::swap( m_indent, other.m_indent ); -// std::swap( m_os, other.m_os ); -// } - - XmlWriter& startElement( std::string const& name ) { - ensureTagClosed(); - newlineIfNecessary(); - stream() << m_indent << "<" << name; - m_tags.push_back( name ); - m_indent += " "; - m_tagIsOpen = true; - return *this; - } - - ScopedElement scopedElement( std::string const& name ) { - ScopedElement scoped( this ); - startElement( name ); - return scoped; - } - - XmlWriter& endElement() { - newlineIfNecessary(); - m_indent = m_indent.substr( 0, m_indent.size()-2 ); - if( m_tagIsOpen ) { - stream() << "/>\n"; - m_tagIsOpen = false; - } - else { - stream() << m_indent << "\n"; - } - m_tags.pop_back(); - return *this; - } - - XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { - if( !name.empty() && !attribute.empty() ) { - stream() << " " << name << "=\""; - writeEncodedText( attribute ); - stream() << "\""; - } - return *this; - } - - XmlWriter& writeAttribute( std::string const& name, bool attribute ) { - stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\""; - return *this; - } - - template - XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { - if( !name.empty() ) - stream() << " " << name << "=\"" << attribute << "\""; - return *this; - } - - XmlWriter& writeText( std::string const& text, bool indent = true ) { - if( !text.empty() ){ - bool tagWasOpen = m_tagIsOpen; - ensureTagClosed(); - if( tagWasOpen && indent ) - stream() << m_indent; - writeEncodedText( text ); - m_needsNewline = true; - } - return *this; - } - - XmlWriter& writeComment( std::string const& text ) { - ensureTagClosed(); - stream() << m_indent << ""; - m_needsNewline = true; - return *this; - } - - XmlWriter& writeBlankLine() { - ensureTagClosed(); - stream() << "\n"; - return *this; - } - - void setStream( std::ostream& os ) { - m_os = &os; - } - - private: - XmlWriter( XmlWriter const& ); - void operator=( XmlWriter const& ); - - std::ostream& stream() { - return *m_os; - } - - void ensureTagClosed() { - if( m_tagIsOpen ) { - stream() << ">\n"; - m_tagIsOpen = false; - } - } - - void newlineIfNecessary() { - if( m_needsNewline ) { - stream() << "\n"; - m_needsNewline = false; - } - } - - void writeEncodedText( std::string const& text ) { - static const char* charsToEncode = "<&\""; - std::string mtext = text; - std::string::size_type pos = mtext.find_first_of( charsToEncode ); - while( pos != std::string::npos ) { - stream() << mtext.substr( 0, pos ); - - switch( mtext[pos] ) { - case '<': - stream() << "<"; - break; - case '&': - stream() << "&"; - break; - case '\"': - stream() << """; - break; - } - mtext = mtext.substr( pos+1 ); - pos = mtext.find_first_of( charsToEncode ); - } - stream() << mtext; - } - - bool m_tagIsOpen; - bool m_needsNewline; - std::vector m_tags; - std::string m_indent; - std::ostream* m_os; - }; - -} -namespace Catch { - class XmlReporter : public StreamingReporterBase { - public: - XmlReporter( ReporterConfig const& _config ) - : StreamingReporterBase( _config ), - m_sectionDepth( 0 ) - {} - - virtual ~XmlReporter(); - - static std::string getDescription() { - return "Reports test results as an XML document"; - } - - public: // StreamingReporterBase - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = true; - return prefs; - } - - virtual void noMatchingTestCases( std::string const& s ) { - StreamingReporterBase::noMatchingTestCases( s ); - } - - virtual void testRunStarting( TestRunInfo const& testInfo ) { - StreamingReporterBase::testRunStarting( testInfo ); - m_xml.setStream( stream ); - m_xml.startElement( "Catch" ); - if( !m_config->name().empty() ) - m_xml.writeAttribute( "name", m_config->name() ); - } - - virtual void testGroupStarting( GroupInfo const& groupInfo ) { - StreamingReporterBase::testGroupStarting( groupInfo ); - m_xml.startElement( "Group" ) - .writeAttribute( "name", groupInfo.name ); - } - - virtual void testCaseStarting( TestCaseInfo const& testInfo ) { - StreamingReporterBase::testCaseStarting(testInfo); - m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); - - if ( m_config->showDurations() == ShowDurations::Always ) - m_testCaseTimer.start(); - } - - virtual void sectionStarting( SectionInfo const& sectionInfo ) { - StreamingReporterBase::sectionStarting( sectionInfo ); - if( m_sectionDepth++ > 0 ) { - m_xml.startElement( "Section" ) - .writeAttribute( "name", trim( sectionInfo.name ) ) - .writeAttribute( "description", sectionInfo.description ); - } - } - - virtual void assertionStarting( AssertionInfo const& ) { } - - virtual bool assertionEnded( AssertionStats const& assertionStats ) { - const AssertionResult& assertionResult = assertionStats.assertionResult; - - // Print any info messages in tags. - if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { - for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); - it != itEnd; - ++it ) { - if( it->type == ResultWas::Info ) { - m_xml.scopedElement( "Info" ) - .writeText( it->message ); - } else if ( it->type == ResultWas::Warning ) { - m_xml.scopedElement( "Warning" ) - .writeText( it->message ); - } - } - } - - // Drop out if result was successful but we're not printing them. - if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) ) - return true; - - // Print the expression if there is one. - if( assertionResult.hasExpression() ) { - m_xml.startElement( "Expression" ) - .writeAttribute( "success", assertionResult.succeeded() ) - .writeAttribute( "type", assertionResult.getTestMacroName() ) - .writeAttribute( "filename", assertionResult.getSourceInfo().file ) - .writeAttribute( "line", assertionResult.getSourceInfo().line ); - - m_xml.scopedElement( "Original" ) - .writeText( assertionResult.getExpression() ); - m_xml.scopedElement( "Expanded" ) - .writeText( assertionResult.getExpandedExpression() ); - } - - // And... Print a result applicable to each result type. - switch( assertionResult.getResultType() ) { - case ResultWas::ThrewException: - m_xml.scopedElement( "Exception" ) - .writeAttribute( "filename", assertionResult.getSourceInfo().file ) - .writeAttribute( "line", assertionResult.getSourceInfo().line ) - .writeText( assertionResult.getMessage() ); - break; - case ResultWas::FatalErrorCondition: - m_xml.scopedElement( "Fatal Error Condition" ) - .writeAttribute( "filename", assertionResult.getSourceInfo().file ) - .writeAttribute( "line", assertionResult.getSourceInfo().line ) - .writeText( assertionResult.getMessage() ); - break; - case ResultWas::Info: - m_xml.scopedElement( "Info" ) - .writeText( assertionResult.getMessage() ); - break; - case ResultWas::Warning: - // Warning will already have been written - break; - case ResultWas::ExplicitFailure: - m_xml.scopedElement( "Failure" ) - .writeText( assertionResult.getMessage() ); - break; - default: - break; - } - - if( assertionResult.hasExpression() ) - m_xml.endElement(); - - return true; - } - - virtual void sectionEnded( SectionStats const& sectionStats ) { - StreamingReporterBase::sectionEnded( sectionStats ); - if( --m_sectionDepth > 0 ) { - XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); - e.writeAttribute( "successes", sectionStats.assertions.passed ); - e.writeAttribute( "failures", sectionStats.assertions.failed ); - e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); - - if ( m_config->showDurations() == ShowDurations::Always ) - e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); - - m_xml.endElement(); - } - } - - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { - StreamingReporterBase::testCaseEnded( testCaseStats ); - XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); - e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); - - if ( m_config->showDurations() == ShowDurations::Always ) - e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); - - m_xml.endElement(); - } - - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { - StreamingReporterBase::testGroupEnded( testGroupStats ); - // TODO: Check testGroupStats.aborting and act accordingly. - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) - .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) - .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); - m_xml.endElement(); - } - - virtual void testRunEnded( TestRunStats const& testRunStats ) { - StreamingReporterBase::testRunEnded( testRunStats ); - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", testRunStats.totals.assertions.passed ) - .writeAttribute( "failures", testRunStats.totals.assertions.failed ) - .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); - m_xml.endElement(); - } - - private: - Timer m_testCaseTimer; - XmlWriter m_xml; - int m_sectionDepth; - }; - - INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) - -} // end namespace Catch - -// #included from: ../reporters/catch_reporter_junit.hpp -#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED - -#include - -namespace Catch { - - class JunitReporter : public CumulativeReporterBase { - public: - JunitReporter( ReporterConfig const& _config ) - : CumulativeReporterBase( _config ), - xml( _config.stream() ) - {} - - ~JunitReporter(); - - static std::string getDescription() { - return "Reports test results in an XML format that looks like Ant's junitreport target"; - } - - virtual void noMatchingTestCases( std::string const& /*spec*/ ) {} - - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = true; - return prefs; - } - - virtual void testRunStarting( TestRunInfo const& runInfo ) { - CumulativeReporterBase::testRunStarting( runInfo ); - xml.startElement( "testsuites" ); - } - - virtual void testGroupStarting( GroupInfo const& groupInfo ) { - suiteTimer.start(); - stdOutForSuite.str(""); - stdErrForSuite.str(""); - unexpectedExceptions = 0; - CumulativeReporterBase::testGroupStarting( groupInfo ); - } - - virtual bool assertionEnded( AssertionStats const& assertionStats ) { - if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) - unexpectedExceptions++; - return CumulativeReporterBase::assertionEnded( assertionStats ); - } - - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { - stdOutForSuite << testCaseStats.stdOut; - stdErrForSuite << testCaseStats.stdErr; - CumulativeReporterBase::testCaseEnded( testCaseStats ); - } - - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { - double suiteTime = suiteTimer.getElapsedSeconds(); - CumulativeReporterBase::testGroupEnded( testGroupStats ); - writeGroup( *m_testGroups.back(), suiteTime ); - } - - virtual void testRunEndedCumulative() { - xml.endElement(); - } - - void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { - XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); - TestGroupStats const& stats = groupNode.value; - xml.writeAttribute( "name", stats.groupInfo.name ); - xml.writeAttribute( "errors", unexpectedExceptions ); - xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); - xml.writeAttribute( "tests", stats.totals.assertions.total() ); - xml.writeAttribute( "hostname", "tbd" ); // !TBD - if( m_config->showDurations() == ShowDurations::Never ) - xml.writeAttribute( "time", "" ); - else - xml.writeAttribute( "time", suiteTime ); - xml.writeAttribute( "timestamp", "tbd" ); // !TBD - - // Write test cases - for( TestGroupNode::ChildNodes::const_iterator - it = groupNode.children.begin(), itEnd = groupNode.children.end(); - it != itEnd; - ++it ) - writeTestCase( **it ); - - xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); - xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); - } - - void writeTestCase( TestCaseNode const& testCaseNode ) { - TestCaseStats const& stats = testCaseNode.value; - - // All test cases have exactly one section - which represents the - // test case itself. That section may have 0-n nested sections - assert( testCaseNode.children.size() == 1 ); - SectionNode const& rootSection = *testCaseNode.children.front(); - - std::string className = stats.testInfo.className; - - if( className.empty() ) { - if( rootSection.childSections.empty() ) - className = "global"; - } - writeSection( className, "", rootSection ); - } - - void writeSection( std::string const& className, - std::string const& rootName, - SectionNode const& sectionNode ) { - std::string name = trim( sectionNode.stats.sectionInfo.name ); - if( !rootName.empty() ) - name = rootName + "/" + name; - - if( !sectionNode.assertions.empty() || - !sectionNode.stdOut.empty() || - !sectionNode.stdErr.empty() ) { - XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); - if( className.empty() ) { - xml.writeAttribute( "classname", name ); - xml.writeAttribute( "name", "root" ); - } - else { - xml.writeAttribute( "classname", className ); - xml.writeAttribute( "name", name ); - } - xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) ); - - writeAssertions( sectionNode ); - - if( !sectionNode.stdOut.empty() ) - xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); - if( !sectionNode.stdErr.empty() ) - xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); - } - for( SectionNode::ChildSections::const_iterator - it = sectionNode.childSections.begin(), - itEnd = sectionNode.childSections.end(); - it != itEnd; - ++it ) - if( className.empty() ) - writeSection( name, "", **it ); - else - writeSection( className, name, **it ); - } - - void writeAssertions( SectionNode const& sectionNode ) { - for( SectionNode::Assertions::const_iterator - it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); - it != itEnd; - ++it ) - writeAssertion( *it ); - } - void writeAssertion( AssertionStats const& stats ) { - AssertionResult const& result = stats.assertionResult; - if( !result.isOk() ) { - std::string elementName; - switch( result.getResultType() ) { - case ResultWas::ThrewException: - case ResultWas::FatalErrorCondition: - elementName = "error"; - break; - case ResultWas::ExplicitFailure: - elementName = "failure"; - break; - case ResultWas::ExpressionFailed: - elementName = "failure"; - break; - case ResultWas::DidntThrowException: - elementName = "failure"; - break; - - // We should never see these here: - case ResultWas::Info: - case ResultWas::Warning: - case ResultWas::Ok: - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - elementName = "internalError"; - break; - } - - XmlWriter::ScopedElement e = xml.scopedElement( elementName ); - - xml.writeAttribute( "message", result.getExpandedExpression() ); - xml.writeAttribute( "type", result.getTestMacroName() ); - - std::ostringstream oss; - if( !result.getMessage().empty() ) - oss << result.getMessage() << "\n"; - for( std::vector::const_iterator - it = stats.infoMessages.begin(), - itEnd = stats.infoMessages.end(); - it != itEnd; - ++it ) - if( it->type == ResultWas::Info ) - oss << it->message << "\n"; - - oss << "at " << result.getSourceInfo(); - xml.writeText( oss.str(), false ); - } - } - - XmlWriter xml; - Timer suiteTimer; - std::ostringstream stdOutForSuite; - std::ostringstream stdErrForSuite; - unsigned int unexpectedExceptions; - }; - - INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) - -} // end namespace Catch - -// #included from: ../reporters/catch_reporter_console.hpp -#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED - -namespace Catch { - - struct ConsoleReporter : StreamingReporterBase { - ConsoleReporter( ReporterConfig const& _config ) - : StreamingReporterBase( _config ), - m_headerPrinted( false ) - {} - - virtual ~ConsoleReporter(); - static std::string getDescription() { - return "Reports test results as plain lines of text"; - } - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = false; - return prefs; - } - - virtual void noMatchingTestCases( std::string const& spec ) { - stream << "No test cases matched '" << spec << "'" << std::endl; - } - - virtual void assertionStarting( AssertionInfo const& ) { - } - - virtual bool assertionEnded( AssertionStats const& _assertionStats ) { - AssertionResult const& result = _assertionStats.assertionResult; - - bool printInfoMessages = true; - - // Drop out if result was successful and we're not printing those - if( !m_config->includeSuccessfulResults() && result.isOk() ) { - if( result.getResultType() != ResultWas::Warning ) - return false; - printInfoMessages = false; - } - - lazyPrint(); - - AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); - printer.print(); - stream << std::endl; - return true; - } - - virtual void sectionStarting( SectionInfo const& _sectionInfo ) { - m_headerPrinted = false; - StreamingReporterBase::sectionStarting( _sectionInfo ); - } - virtual void sectionEnded( SectionStats const& _sectionStats ) { - if( _sectionStats.missingAssertions ) { - lazyPrint(); - Colour colour( Colour::ResultError ); - if( m_sectionStack.size() > 1 ) - stream << "\nNo assertions in section"; - else - stream << "\nNo assertions in test case"; - stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; - } - if( m_headerPrinted ) { - if( m_config->showDurations() == ShowDurations::Always ) - stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl; - m_headerPrinted = false; - } - else { - if( m_config->showDurations() == ShowDurations::Always ) - stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl; - } - StreamingReporterBase::sectionEnded( _sectionStats ); - } - - virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) { - StreamingReporterBase::testCaseEnded( _testCaseStats ); - m_headerPrinted = false; - } - virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) { - if( currentGroupInfo.used ) { - printSummaryDivider(); - stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; - printTotals( _testGroupStats.totals ); - stream << "\n" << std::endl; - } - StreamingReporterBase::testGroupEnded( _testGroupStats ); - } - virtual void testRunEnded( TestRunStats const& _testRunStats ) { - printTotalsDivider( _testRunStats.totals ); - printTotals( _testRunStats.totals ); - stream << std::endl; - StreamingReporterBase::testRunEnded( _testRunStats ); - } - - private: - - class AssertionPrinter { - void operator= ( AssertionPrinter const& ); - public: - AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) - : stream( _stream ), - stats( _stats ), - result( _stats.assertionResult ), - colour( Colour::None ), - message( result.getMessage() ), - messages( _stats.infoMessages ), - printInfoMessages( _printInfoMessages ) - { - switch( result.getResultType() ) { - case ResultWas::Ok: - colour = Colour::Success; - passOrFail = "PASSED"; - //if( result.hasMessage() ) - if( _stats.infoMessages.size() == 1 ) - messageLabel = "with message"; - if( _stats.infoMessages.size() > 1 ) - messageLabel = "with messages"; - break; - case ResultWas::ExpressionFailed: - if( result.isOk() ) { - colour = Colour::Success; - passOrFail = "FAILED - but was ok"; - } - else { - colour = Colour::Error; - passOrFail = "FAILED"; - } - if( _stats.infoMessages.size() == 1 ) - messageLabel = "with message"; - if( _stats.infoMessages.size() > 1 ) - messageLabel = "with messages"; - break; - case ResultWas::ThrewException: - colour = Colour::Error; - passOrFail = "FAILED"; - messageLabel = "due to unexpected exception with message"; - break; - case ResultWas::FatalErrorCondition: - colour = Colour::Error; - passOrFail = "FAILED"; - messageLabel = "due to a fatal error condition"; - break; - case ResultWas::DidntThrowException: - colour = Colour::Error; - passOrFail = "FAILED"; - messageLabel = "because no exception was thrown where one was expected"; - break; - case ResultWas::Info: - messageLabel = "info"; - break; - case ResultWas::Warning: - messageLabel = "warning"; - break; - case ResultWas::ExplicitFailure: - passOrFail = "FAILED"; - colour = Colour::Error; - if( _stats.infoMessages.size() == 1 ) - messageLabel = "explicitly with message"; - if( _stats.infoMessages.size() > 1 ) - messageLabel = "explicitly with messages"; - break; - // These cases are here to prevent compiler warnings - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - passOrFail = "** internal error **"; - colour = Colour::Error; - break; - } - } - - void print() const { - printSourceInfo(); - if( stats.totals.assertions.total() > 0 ) { - if( result.isOk() ) - stream << "\n"; - printResultType(); - printOriginalExpression(); - printReconstructedExpression(); - } - else { - stream << "\n"; - } - printMessage(); - } - - private: - void printResultType() const { - if( !passOrFail.empty() ) { - Colour colourGuard( colour ); - stream << passOrFail << ":\n"; - } - } - void printOriginalExpression() const { - if( result.hasExpression() ) { - Colour colourGuard( Colour::OriginalExpression ); - stream << " "; - stream << result.getExpressionInMacro(); - stream << "\n"; - } - } - void printReconstructedExpression() const { - if( result.hasExpandedExpression() ) { - stream << "with expansion:\n"; - Colour colourGuard( Colour::ReconstructedExpression ); - stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n"; - } - } - void printMessage() const { - if( !messageLabel.empty() ) - stream << messageLabel << ":" << "\n"; - for( std::vector::const_iterator it = messages.begin(), itEnd = messages.end(); - it != itEnd; - ++it ) { - // If this assertion is a warning ignore any INFO messages - if( printInfoMessages || it->type != ResultWas::Info ) - stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n"; - } - } - void printSourceInfo() const { - Colour colourGuard( Colour::FileName ); - stream << result.getSourceInfo() << ": "; - } - - std::ostream& stream; - AssertionStats const& stats; - AssertionResult const& result; - Colour::Code colour; - std::string passOrFail; - std::string messageLabel; - std::string message; - std::vector messages; - bool printInfoMessages; - }; - - void lazyPrint() { - - if( !currentTestRunInfo.used ) - lazyPrintRunInfo(); - if( !currentGroupInfo.used ) - lazyPrintGroupInfo(); - - if( !m_headerPrinted ) { - printTestCaseAndSectionHeader(); - m_headerPrinted = true; - } - } - void lazyPrintRunInfo() { - stream << "\n" << getLineOfChars<'~'>() << "\n"; - Colour colour( Colour::SecondaryText ); - stream << currentTestRunInfo->name - << " is a Catch v" << libraryVersion.majorVersion << "." - << libraryVersion.minorVersion << " b" - << libraryVersion.buildNumber; - if( libraryVersion.branchName != std::string( "master" ) ) - stream << " (" << libraryVersion.branchName << ")"; - stream << " host application.\n" - << "Run with -? for options\n\n"; - - if( m_config->rngSeed() != 0 ) - stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; - - currentTestRunInfo.used = true; - } - void lazyPrintGroupInfo() { - if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { - printClosedHeader( "Group: " + currentGroupInfo->name ); - currentGroupInfo.used = true; - } - } - void printTestCaseAndSectionHeader() { - assert( !m_sectionStack.empty() ); - printOpenHeader( currentTestCaseInfo->name ); - - if( m_sectionStack.size() > 1 ) { - Colour colourGuard( Colour::Headers ); - - std::vector::const_iterator - it = m_sectionStack.begin()+1, // Skip first section (test case) - itEnd = m_sectionStack.end(); - for( ; it != itEnd; ++it ) - printHeaderString( it->name, 2 ); - } - - SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; - - if( !lineInfo.empty() ){ - stream << getLineOfChars<'-'>() << "\n"; - Colour colourGuard( Colour::FileName ); - stream << lineInfo << "\n"; - } - stream << getLineOfChars<'.'>() << "\n" << std::endl; - } - - void printClosedHeader( std::string const& _name ) { - printOpenHeader( _name ); - stream << getLineOfChars<'.'>() << "\n"; - } - void printOpenHeader( std::string const& _name ) { - stream << getLineOfChars<'-'>() << "\n"; - { - Colour colourGuard( Colour::Headers ); - printHeaderString( _name ); - } - } - - // if string has a : in first line will set indent to follow it on - // subsequent lines - void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { - std::size_t i = _string.find( ": " ); - if( i != std::string::npos ) - i+=2; - else - i = 0; - stream << Text( _string, TextAttributes() - .setIndent( indent+i) - .setInitialIndent( indent ) ) << "\n"; - } - - struct SummaryColumn { - - SummaryColumn( std::string const& _label, Colour::Code _colour ) - : label( _label ), - colour( _colour ) - {} - SummaryColumn addRow( std::size_t count ) { - std::ostringstream oss; - oss << count; - std::string row = oss.str(); - for( std::vector::iterator it = rows.begin(); it != rows.end(); ++it ) { - while( it->size() < row.size() ) - *it = " " + *it; - while( it->size() > row.size() ) - row = " " + row; - } - rows.push_back( row ); - return *this; - } - - std::string label; - Colour::Code colour; - std::vector rows; - - }; - - void printTotals( Totals const& totals ) { - if( totals.testCases.total() == 0 ) { - stream << Colour( Colour::Warning ) << "No tests ran\n"; - } - else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) { - stream << Colour( Colour::ResultSuccess ) << "All tests passed"; - stream << " (" - << pluralise( totals.assertions.passed, "assertion" ) << " in " - << pluralise( totals.testCases.passed, "test case" ) << ")" - << "\n"; - } - else { - - std::vector columns; - columns.push_back( SummaryColumn( "", Colour::None ) - .addRow( totals.testCases.total() ) - .addRow( totals.assertions.total() ) ); - columns.push_back( SummaryColumn( "passed", Colour::Success ) - .addRow( totals.testCases.passed ) - .addRow( totals.assertions.passed ) ); - columns.push_back( SummaryColumn( "failed", Colour::ResultError ) - .addRow( totals.testCases.failed ) - .addRow( totals.assertions.failed ) ); - columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) - .addRow( totals.testCases.failedButOk ) - .addRow( totals.assertions.failedButOk ) ); - - printSummaryRow( "test cases", columns, 0 ); - printSummaryRow( "assertions", columns, 1 ); - } - } - void printSummaryRow( std::string const& label, std::vector const& cols, std::size_t row ) { - for( std::vector::const_iterator it = cols.begin(); it != cols.end(); ++it ) { - std::string value = it->rows[row]; - if( it->label.empty() ) { - stream << label << ": "; - if( value != "0" ) - stream << value; - else - stream << Colour( Colour::Warning ) << "- none -"; - } - else if( value != "0" ) { - stream << Colour( Colour::LightGrey ) << " | "; - stream << Colour( it->colour ) - << value << " " << it->label; - } - } - stream << "\n"; - } - - static std::size_t makeRatio( std::size_t number, std::size_t total ) { - std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; - return ( ratio == 0 && number > 0 ) ? 1 : ratio; - } - static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { - if( i > j && i > k ) - return i; - else if( j > k ) - return j; - else - return k; - } - - void printTotalsDivider( Totals const& totals ) { - if( totals.testCases.total() > 0 ) { - std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); - std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); - std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); - while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) - findMax( failedRatio, failedButOkRatio, passedRatio )++; - while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) - findMax( failedRatio, failedButOkRatio, passedRatio )--; - - stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); - stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); - if( totals.testCases.allPassed() ) - stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); - else - stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); - } - else { - stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); - } - stream << "\n"; - } - void printSummaryDivider() { - stream << getLineOfChars<'-'>() << "\n"; - } - - private: - bool m_headerPrinted; - }; - - INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) - -} // end namespace Catch - -// #included from: ../reporters/catch_reporter_compact.hpp -#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED - -namespace Catch { - - struct CompactReporter : StreamingReporterBase { - - CompactReporter( ReporterConfig const& _config ) - : StreamingReporterBase( _config ) - {} - - virtual ~CompactReporter(); - - static std::string getDescription() { - return "Reports test results on a single line, suitable for IDEs"; - } - - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = false; - return prefs; - } - - virtual void noMatchingTestCases( std::string const& spec ) { - stream << "No test cases matched '" << spec << "'" << std::endl; - } - - virtual void assertionStarting( AssertionInfo const& ) { - } - - virtual bool assertionEnded( AssertionStats const& _assertionStats ) { - AssertionResult const& result = _assertionStats.assertionResult; - - bool printInfoMessages = true; - - // Drop out if result was successful and we're not printing those - if( !m_config->includeSuccessfulResults() && result.isOk() ) { - if( result.getResultType() != ResultWas::Warning ) - return false; - printInfoMessages = false; - } - - AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); - printer.print(); - - stream << std::endl; - return true; - } - - virtual void testRunEnded( TestRunStats const& _testRunStats ) { - printTotals( _testRunStats.totals ); - stream << "\n" << std::endl; - StreamingReporterBase::testRunEnded( _testRunStats ); - } - - private: - class AssertionPrinter { - void operator= ( AssertionPrinter const& ); - public: - AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) - : stream( _stream ) - , stats( _stats ) - , result( _stats.assertionResult ) - , messages( _stats.infoMessages ) - , itMessage( _stats.infoMessages.begin() ) - , printInfoMessages( _printInfoMessages ) - {} - - void print() { - printSourceInfo(); - - itMessage = messages.begin(); - - switch( result.getResultType() ) { - case ResultWas::Ok: - printResultType( Colour::ResultSuccess, passedString() ); - printOriginalExpression(); - printReconstructedExpression(); - if ( ! result.hasExpression() ) - printRemainingMessages( Colour::None ); - else - printRemainingMessages(); - break; - case ResultWas::ExpressionFailed: - if( result.isOk() ) - printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); - else - printResultType( Colour::Error, failedString() ); - printOriginalExpression(); - printReconstructedExpression(); - printRemainingMessages(); - break; - case ResultWas::ThrewException: - printResultType( Colour::Error, failedString() ); - printIssue( "unexpected exception with message:" ); - printMessage(); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::FatalErrorCondition: - printResultType( Colour::Error, failedString() ); - printIssue( "fatal error condition with message:" ); - printMessage(); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::DidntThrowException: - printResultType( Colour::Error, failedString() ); - printIssue( "expected exception, got none" ); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::Info: - printResultType( Colour::None, "info" ); - printMessage(); - printRemainingMessages(); - break; - case ResultWas::Warning: - printResultType( Colour::None, "warning" ); - printMessage(); - printRemainingMessages(); - break; - case ResultWas::ExplicitFailure: - printResultType( Colour::Error, failedString() ); - printIssue( "explicitly" ); - printRemainingMessages( Colour::None ); - break; - // These cases are here to prevent compiler warnings - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - printResultType( Colour::Error, "** internal error **" ); - break; - } - } - - private: - // Colour::LightGrey - - static Colour::Code dimColour() { return Colour::FileName; } - -#ifdef CATCH_PLATFORM_MAC - static const char* failedString() { return "FAILED"; } - static const char* passedString() { return "PASSED"; } -#else - static const char* failedString() { return "failed"; } - static const char* passedString() { return "passed"; } -#endif - - void printSourceInfo() const { - Colour colourGuard( Colour::FileName ); - stream << result.getSourceInfo() << ":"; - } - - void printResultType( Colour::Code colour, std::string passOrFail ) const { - if( !passOrFail.empty() ) { - { - Colour colourGuard( colour ); - stream << " " << passOrFail; - } - stream << ":"; - } - } - - void printIssue( std::string issue ) const { - stream << " " << issue; - } - - void printExpressionWas() { - if( result.hasExpression() ) { - stream << ";"; - { - Colour colour( dimColour() ); - stream << " expression was:"; - } - printOriginalExpression(); - } - } - - void printOriginalExpression() const { - if( result.hasExpression() ) { - stream << " " << result.getExpression(); - } - } - - void printReconstructedExpression() const { - if( result.hasExpandedExpression() ) { - { - Colour colour( dimColour() ); - stream << " for: "; - } - stream << result.getExpandedExpression(); - } - } - - void printMessage() { - if ( itMessage != messages.end() ) { - stream << " '" << itMessage->message << "'"; - ++itMessage; - } - } - - void printRemainingMessages( Colour::Code colour = dimColour() ) { - if ( itMessage == messages.end() ) - return; - - // using messages.end() directly yields compilation error: - std::vector::const_iterator itEnd = messages.end(); - const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); - - { - Colour colourGuard( colour ); - stream << " with " << pluralise( N, "message" ) << ":"; - } - - for(; itMessage != itEnd; ) { - // If this assertion is a warning ignore any INFO messages - if( printInfoMessages || itMessage->type != ResultWas::Info ) { - stream << " '" << itMessage->message << "'"; - if ( ++itMessage != itEnd ) { - Colour colourGuard( dimColour() ); - stream << " and"; - } - } - } - } - - private: - std::ostream& stream; - AssertionStats const& stats; - AssertionResult const& result; - std::vector messages; - std::vector::const_iterator itMessage; - bool printInfoMessages; - }; - - // Colour, message variants: - // - white: No tests ran. - // - red: Failed [both/all] N test cases, failed [both/all] M assertions. - // - white: Passed [both/all] N test cases (no assertions). - // - red: Failed N tests cases, failed M assertions. - // - green: Passed [both/all] N tests cases with M assertions. - - std::string bothOrAll( std::size_t count ) const { - return count == 1 ? "" : count == 2 ? "both " : "all " ; - } - - void printTotals( const Totals& totals ) const { - if( totals.testCases.total() == 0 ) { - stream << "No tests ran."; - } - else if( totals.testCases.failed == totals.testCases.total() ) { - Colour colour( Colour::ResultError ); - const std::string qualify_assertions_failed = - totals.assertions.failed == totals.assertions.total() ? - bothOrAll( totals.assertions.failed ) : ""; - stream << - "Failed " << bothOrAll( totals.testCases.failed ) - << pluralise( totals.testCases.failed, "test case" ) << ", " - "failed " << qualify_assertions_failed << - pluralise( totals.assertions.failed, "assertion" ) << "."; - } - else if( totals.assertions.total() == 0 ) { - stream << - "Passed " << bothOrAll( totals.testCases.total() ) - << pluralise( totals.testCases.total(), "test case" ) - << " (no assertions)."; - } - else if( totals.assertions.failed ) { - Colour colour( Colour::ResultError ); - stream << - "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " - "failed " << pluralise( totals.assertions.failed, "assertion" ) << "."; - } - else { - Colour colour( Colour::ResultSuccess ); - stream << - "Passed " << bothOrAll( totals.testCases.passed ) - << pluralise( totals.testCases.passed, "test case" ) << - " with " << pluralise( totals.assertions.passed, "assertion" ) << "."; - } - } - }; - - INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) - -} // end namespace Catch - -namespace Catch { - NonCopyable::~NonCopyable() {} - IShared::~IShared() {} - StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} - IContext::~IContext() {} - IResultCapture::~IResultCapture() {} - ITestCase::~ITestCase() {} - ITestCaseRegistry::~ITestCaseRegistry() {} - IRegistryHub::~IRegistryHub() {} - IMutableRegistryHub::~IMutableRegistryHub() {} - IExceptionTranslator::~IExceptionTranslator() {} - IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} - IReporter::~IReporter() {} - IReporterFactory::~IReporterFactory() {} - IReporterRegistry::~IReporterRegistry() {} - IStreamingReporter::~IStreamingReporter() {} - AssertionStats::~AssertionStats() {} - SectionStats::~SectionStats() {} - TestCaseStats::~TestCaseStats() {} - TestGroupStats::~TestGroupStats() {} - TestRunStats::~TestRunStats() {} - CumulativeReporterBase::SectionNode::~SectionNode() {} - CumulativeReporterBase::~CumulativeReporterBase() {} - - StreamingReporterBase::~StreamingReporterBase() {} - ConsoleReporter::~ConsoleReporter() {} - CompactReporter::~CompactReporter() {} - IRunner::~IRunner() {} - IMutableContext::~IMutableContext() {} - IConfig::~IConfig() {} - XmlReporter::~XmlReporter() {} - JunitReporter::~JunitReporter() {} - TestRegistry::~TestRegistry() {} - FreeFunctionTestCase::~FreeFunctionTestCase() {} - IGeneratorInfo::~IGeneratorInfo() {} - IGeneratorsForTest::~IGeneratorsForTest() {} - TestSpec::Pattern::~Pattern() {} - TestSpec::NamePattern::~NamePattern() {} - TestSpec::TagPattern::~TagPattern() {} - TestSpec::ExcludedPattern::~ExcludedPattern() {} - - Matchers::Impl::StdString::Equals::~Equals() {} - Matchers::Impl::StdString::Contains::~Contains() {} - Matchers::Impl::StdString::StartsWith::~StartsWith() {} - Matchers::Impl::StdString::EndsWith::~EndsWith() {} - - void Config::dummy() {} -} - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -#endif - -#ifdef CATCH_CONFIG_MAIN -// #included from: internal/catch_default_main.hpp -#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED - -#ifndef __OBJC__ - -// Standard C/C++ main entry point -int main (int argc, char * const argv[]) { - return Catch::Session().run( argc, argv ); -} - -#else // __OBJC__ - -// Objective-C entry point -int main (int argc, char * const argv[]) { -#if !CATCH_ARC_ENABLED - NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; -#endif - - Catch::registerTestMethods(); - int result = Catch::Session().run( argc, (char* const*)argv ); - -#if !CATCH_ARC_ENABLED - [pool drain]; -#endif - - return result; -} - -#endif // __OBJC__ - -#endif - -#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED -# undef CLARA_CONFIG_MAIN -#endif - -////// - -// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ -#ifdef CATCH_CONFIG_PREFIX_ALL - -#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) -#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) - -#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS" ) -#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) -#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) - -#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) -#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" ) -#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" ) -#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" ) -#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" ) - -#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) -#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) -#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) - -#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) -#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" ) - -#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) -#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg ) -#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) -#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) -#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) - -#ifdef CATCH_CONFIG_VARIADIC_MACROS - #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) - #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) - #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) - #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) - #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) - #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) -#else - #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) - #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) - #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) - #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) - #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) - #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) -#endif -#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) - -#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) -#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) - -#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) - -// "BDD-style" convenience wrappers -#ifdef CATCH_CONFIG_VARIADIC_MACROS -#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) -#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) -#else -#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) -#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) -#endif -#define CATCH_GIVEN( desc ) CATCH_SECTION( "Given: " desc, "" ) -#define CATCH_WHEN( desc ) CATCH_SECTION( " When: " desc, "" ) -#define CATCH_AND_WHEN( desc ) CATCH_SECTION( " And: " desc, "" ) -#define CATCH_THEN( desc ) CATCH_SECTION( " Then: " desc, "" ) -#define CATCH_AND_THEN( desc ) CATCH_SECTION( " And: " desc, "" ) - -// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required -#else - -#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) -#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) - -#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "REQUIRE_THROWS" ) -#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) -#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) - -#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) -#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" ) -#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" ) -#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) -#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) - -#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS" ) -#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) -#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) - -#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) -#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" ) - -#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) -#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg ) -#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) -#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) -#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) - -#ifdef CATCH_CONFIG_VARIADIC_MACROS - #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) - #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) - #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) - #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) - #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) - #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) -#else - #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) - #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) - #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) - #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) - #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) - #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) -#endif -#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) - -#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) -#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) - -#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) - -#endif - -#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) - -// "BDD-style" convenience wrappers -#ifdef CATCH_CONFIG_VARIADIC_MACROS -#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) -#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) -#else -#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) -#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) -#endif -#define GIVEN( desc ) SECTION( " Given: " desc, "" ) -#define WHEN( desc ) SECTION( " When: " desc, "" ) -#define AND_WHEN( desc ) SECTION( "And when: " desc, "" ) -#define THEN( desc ) SECTION( " Then: " desc, "" ) -#define AND_THEN( desc ) SECTION( " And: " desc, "" ) - -using Catch::Detail::Approx; - -// #included from: internal/catch_reenable_warnings.h - -#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED - -#ifdef __clang__ -#pragma clang diagnostic pop -#elif defined __GNUC__ -#pragma GCC diagnostic pop -#endif - -#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED - diff --git a/test/download_catch.sh b/test/download_catch.sh new file mode 100755 index 00000000..b373a2c4 --- /dev/null +++ b/test/download_catch.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +wget -c https://raw.githubusercontent.com/philsquared/Catch/develop/single_include/catch.hpp From 36574a8d0fdfa88fb24003b246e11fcd9083b109 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 22 May 2015 12:14:17 -0700 Subject: [PATCH 1129/1866] Tests that range works as a forward iterator --- test/helpers.hpp | 4 ++++ test/test_range.cpp | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/test/helpers.hpp b/test/helpers.hpp index 7c36ca89..0be552b2 100644 --- a/test/helpers.hpp +++ b/test/helpers.hpp @@ -188,6 +188,10 @@ struct IsIterator () == std::declval()) // == >> : std::true_type { }; +template +struct IsForwardIterator : std::integral_constant::value && std::is_default_constructible::value> { }; + } #endif diff --git a/test/test_range.cpp b/test/test_range.cpp index d5dc6d29..83e285fe 100644 --- a/test/test_range.cpp +++ b/test/test_range.cpp @@ -191,7 +191,9 @@ TEST_CASE("range: using doubles detects empty ranges", "[range]") { REQUIRE(std::begin(r2) == std::end(r2)); } -TEST_CASE("range: iterator meets requirements", "[range]") { +TEST_CASE("range: iterator meets forward iterator requirements", "[range]") { auto r = range(5); - REQUIRE( itertest::IsIterator::value ); + auto r2 = range(5.0); + REQUIRE( itertest::IsForwardIterator::value ); + REQUIRE( itertest::IsForwardIterator::value ); } From 5e9d1c31117c7a08545662211899fbc1edd75e73 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 22 May 2015 12:16:39 -0700 Subject: [PATCH 1130/1866] makes range iterator a forward iterator --- range.hpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/range.hpp b/range.hpp index 7a0017d3..960dba42 100644 --- a/range.hpp +++ b/range.hpp @@ -45,7 +45,7 @@ namespace iter { friend Range range(T, T); friend Range range(T, T, T); private: - const T start; + const T start; const T stop; const T step; @@ -63,7 +63,7 @@ namespace iter { public: class Iterator - : public std::iterator + : public std::iterator { private: T value; @@ -82,6 +82,8 @@ namespace iter { && !(this->step < 0 && this->value <= other.value); } public: + Iterator() =default; + Iterator(T val, T in_step) : value{val}, step{in_step} @@ -165,7 +167,7 @@ namespace iter { { } public: class Iterator - : public std::iterator + : public std::iterator { private: T start; @@ -174,6 +176,8 @@ namespace iter { unsigned long steps_taken =0; public: + Iterator() =default; + Iterator(T in_start, T in_step) : start{in_start}, value{in_start}, From cf1fa5965891e6a37c4c11b472dfa227603650b2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 22 May 2015 14:37:16 -0700 Subject: [PATCH 1131/1866] adds more forward_iterator range tests --- test/test_range.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/test_range.cpp b/test/test_range.cpp index 83e285fe..3927eadc 100644 --- a/test/test_range.cpp +++ b/test/test_range.cpp @@ -146,6 +146,22 @@ TEST_CASE("range: works with a variable start, stop, and step", "[range]") { } +TEST_CASE("range: forward iterator checks", "[range]") { + auto r = range(10); + auto it1 = std::begin(r); + auto it2 = std::begin(r); + REQUIRE_FALSE( it1 != it2 ); + REQUIRE( it1 == it2 ); + ++it1; + REQUIRE( it1 != it2 ); + ++it2; + REQUIRE( it1 == it2 ); + auto it3 = it1++; + REQUIRE( it3 == it2 ); + auto it4 = ++it3; + REQUIRE( it4 == it3 ); +} + using FVec = const std::vector; TEST_CASE("range: using doubles", "[range]") { From 5adba3db5bbff69101b656feb05f5b1d345a07a6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 22 May 2015 14:37:32 -0700 Subject: [PATCH 1132/1866] range can compare arbitrary iterators --- range.hpp | 61 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/range.hpp b/range.hpp index 960dba42..c11b1bc7 100644 --- a/range.hpp +++ b/range.hpp @@ -18,6 +18,7 @@ #include #include #include +#include namespace iter { @@ -68,25 +69,45 @@ namespace iter { private: T value; T step; + bool is_end; // compare unsigned values - bool not_equal_to( - const Iterator& other, std::true_type ) const { - return this->value < other.value; + static bool not_equal_to_impl( + const Iterator& iter, const Iterator& end_iter, + std::true_type ) { + assert(!iter.is_end); + assert(end_iter.is_end); + return iter.value < end_iter.value; } // compare signed values - bool not_equal_to( - const Iterator& other, std::false_type) const { - return !(this->step > 0 && this->value >= other.value) - && !(this->step < 0 && this->value <= other.value); + static bool not_equal_to_impl( + const Iterator& iter, const Iterator& end_iter, + std::false_type) { + assert(!iter.is_end); + assert(end_iter.is_end); + return !(iter.step > 0 && iter.value >= end_iter.value) + && !(iter.step < 0 && iter.value <= end_iter.value); + } + + static bool not_equal_to_end( + const Iterator& lhs, const Iterator& rhs) { + if (rhs.is_end) { + return not_equal_to_impl( + lhs, rhs, std::is_unsigned{}); + } else { + return not_equal_to_impl( + rhs, lhs, std::is_unsigned{}); + } } + public: Iterator() =default; - Iterator(T val, T in_step) + Iterator(T val, T in_step, bool in_is_end) : value{val}, - step{in_step} + step{in_step}, + is_end{in_is_end} { } T operator*() const { @@ -121,9 +142,15 @@ namespace iter { // Another way to think about it is that the "end" // iterator represents the range of values that are invalid // 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()); + bool operator!=(const Iterator& other) const { + if (this->is_end && other.is_end) { + return false; + } + + if (!this->is_end && !other.is_end) { + return this->value != other.value; + } + return not_equal_to_end(*this, other); } bool operator==(const Iterator& other) const { @@ -132,25 +159,25 @@ namespace iter { }; Iterator begin() const { - return {start, step}; + return {start, step, false}; } - Iterator end() const { - return {stop, step}; + Iterator end() const { + return {stop, step, true}; } }; // This specialization is used for floating point types. Instead of // adding one "step" each time ++ is called on the iterator, the value // is recalculated as start + (steps_taken + step_size) to avoid - // accumulating floating point inaccuracies + // accumulating floating point inaccuracies template class Range { friend Range range(T); friend Range range(T, T); friend Range range(T, T, T); private: - const T start; + const T start; const T stop; const T step; From e30289f19435517a489ce972972428ca38545d2f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 22 May 2015 17:24:19 -0700 Subject: [PATCH 1133/1866] adds more forward_iterator tests --- test/test_range.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/test_range.cpp b/test/test_range.cpp index 3927eadc..11c651c8 100644 --- a/test/test_range.cpp +++ b/test/test_range.cpp @@ -148,6 +148,24 @@ TEST_CASE("range: works with a variable start, stop, and step", "[range]") { TEST_CASE("range: forward iterator checks", "[range]") { auto r = range(10); + REQUIRE( std::end(r) == std::end(r) ); + auto it1 = std::begin(r); + auto it2 = std::begin(r); + REQUIRE_FALSE( it1 != it2 ); + REQUIRE( it1 == it2 ); + ++it1; + REQUIRE( it1 != it2 ); + ++it2; + REQUIRE( it1 == it2 ); + auto it3 = it1++; + REQUIRE( it3 == it2 ); + auto it4 = ++it3; + REQUIRE( it4 == it3 ); +} + +TEST_CASE("range: forward iterator with double, checks", "[range]") { + auto r = range(10.0); + REQUIRE( std::end(r) == std::end(r) ); auto it1 = std::begin(r); auto it2 = std::begin(r); REQUIRE_FALSE( it1 != it2 ); From 6565639b1a0880cdd93d3dcd13b37ecb71fe36b0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 22 May 2015 17:25:18 -0700 Subject: [PATCH 1134/1866] Moves the float specialization into a helper class Rather than fully specializing Range for floats, just specialize a small part of the iterator. --- range.hpp | 219 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 112 insertions(+), 107 deletions(-) diff --git a/range.hpp b/range.hpp index c11b1bc7..175d2604 100644 --- a/range.hpp +++ b/range.hpp @@ -22,6 +22,87 @@ namespace iter { + template ::value> + class RangeIterData; + + // everything except floats + template + class RangeIterData { + private: + T value_{}; + T step_{}; + public: + RangeIterData() =default; + RangeIterData(T in_value, T in_step) + : value_{in_value}, + step_{in_step} + { } + + T value() const { + return this->value_; + } + + T step() const { + return this->step_; + } + + void inc() { + this->value_ += step_; + } + + bool operator==(const RangeIterData& other) const { + return this->value_ == other.value_; + } + + bool operator!=(const RangeIterData& other) const { + return !(*this == other); + } + }; + + // float data + template + class RangeIterData { + private: + T start_{}; + T value_{}; + T step_{}; + unsigned long steps_taken{}; + public: + RangeIterData() =default; + RangeIterData(T in_start, T in_step) + : start_{in_start}, + value_{in_start}, + step_{in_step} + { } + + T value() const { + return this->value_; + } + + T step() const { + return this->step_; + } + + void inc() { + ++this->steps_taken; + value_ = this->start_ + + (this->step_ * this->steps_taken); + } + + bool operator==(const RangeIterData& other) const { + // if the difference between the two values is less than the + // step size, they are considered equal + T diff = this->value_ < other.value_ ? + other.value_ - this->value_ : this->value_ - other.value_; + return diff < step_; + } + + bool operator!=(const RangeIterData& other) const { + return !(*this == other); + } + }; + + // Thrown when step 0 occurs class RangeException : public std::exception { const char *what() const noexcept override { @@ -29,22 +110,22 @@ namespace iter { } }; - template + template class Range; - template ::value> - Range range(T); - template ::value> - Range range(T, T); - template ::value> - Range range(T, T, T); + template + Range range(T); + template + Range range(T, T); + template + Range range(T, T, T); // General version for everything not a float - template + template class Range { - friend Range range(T); - friend Range range(T, T); - friend Range range(T, T, T); + friend Range range(T); + friend Range range(T, T); + friend Range range(T, T, T); private: const T start; const T stop; @@ -67,8 +148,7 @@ namespace iter { : public std::iterator { private: - T value; - T step; + RangeIterData data; bool is_end; // compare unsigned values @@ -77,7 +157,7 @@ namespace iter { std::true_type ) { assert(!iter.is_end); assert(end_iter.is_end); - return iter.value < end_iter.value; + return iter.data.value() < end_iter.data.value(); } // compare signed values @@ -86,8 +166,10 @@ namespace iter { std::false_type) { assert(!iter.is_end); assert(end_iter.is_end); - return !(iter.step > 0 && iter.value >= end_iter.value) - && !(iter.step < 0 && iter.value <= end_iter.value); + return !(iter.data.step() > 0 && iter.data.value() + >= end_iter.data.value()) + && !(iter.data.step() < 0 && iter.data.value() + <= end_iter.data.value()); } static bool not_equal_to_end( @@ -104,18 +186,17 @@ namespace iter { public: Iterator() =default; - Iterator(T val, T in_step, bool in_is_end) - : value{val}, - step{in_step}, + Iterator(T in_value, T in_step, bool in_is_end) + : data(in_value, in_step), is_end{in_is_end} { } T operator*() const { - return this->value; + return this->data.value(); } Iterator& operator++() { - this->value += this->step; + this->data.inc(); return *this; } @@ -142,13 +223,17 @@ namespace iter { // Another way to think about it is that the "end" // iterator represents the range of values that are invalid // So, if an iterator is not equal to that, it is valid + // + // Two end iterators will compare equal + // + // Two non-end iterators will compare by their stored values bool operator!=(const Iterator& other) const { if (this->is_end && other.is_end) { return false; } if (!this->is_end && !other.is_end) { - return this->value != other.value; + return this->data != other.data; } return not_equal_to_end(*this, other); } @@ -167,98 +252,18 @@ namespace iter { } }; - // This specialization is used for floating point types. Instead of - // adding one "step" each time ++ is called on the iterator, the value - // is recalculated as start + (steps_taken + step_size) to avoid - // accumulating floating point inaccuracies template - class Range { - friend Range range(T); - friend Range range(T, T); - friend Range range(T, T, T); - private: - const T start; - const T stop; - const T step; - - Range(T in_stop) - : start{0}, - stop{in_stop}, - step{1} - { } - - Range(T in_start, T in_stop, T in_step =1) - : start{in_start}, - stop{in_stop}, - step{in_step} - { } - public: - class Iterator - : public std::iterator - { - private: - T start; - T value; - T step; - unsigned long steps_taken =0; - - public: - Iterator() =default; - - Iterator(T in_start, T in_step) - : start{in_start}, - value{in_start}, - step{in_step} - { } - - bool operator!=(const Iterator& other) const { - return !(this->step > 0 && this->value >= other.value) - && !(this->step < 0 && this->value <= other.value); - } - - bool operator==(const Iterator& other) const { - return !(*this != other); - } - - T operator*() const { - return this->value; - } - - Iterator& operator++() { - ++this->steps_taken; - this->value = this->start + - (this->step * this->steps_taken); - return *this; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - }; - - Iterator begin() const { - return {start, step}; - } - - Iterator end() const { - return {stop, step}; - } - }; - - template - Range range(T stop) { + Range range(T stop) { return {stop}; } - template - Range range(T start, T stop) { + template + Range range(T start, T stop) { return {start, stop}; } - template - Range range(T start, T stop, T step) { + template + Range range(T start, T stop, T step) { if (step == 0) { throw RangeException{}; } From fa8dfdad71cc39c06b9d67cbf8d2c2a804d60e40 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 26 May 2015 11:31:36 -0700 Subject: [PATCH 1135/1866] range operator* returns reference instead of value I believe this meets the ForwardIterator requirements. --- range.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/range.hpp b/range.hpp index 175d2604..0bfd5051 100644 --- a/range.hpp +++ b/range.hpp @@ -38,7 +38,7 @@ namespace iter { step_{in_step} { } - T value() const { + const T& value() const { return this->value_; } @@ -75,7 +75,7 @@ namespace iter { step_{in_step} { } - T value() const { + const T& value() const { return this->value_; } @@ -145,7 +145,8 @@ namespace iter { public: class Iterator - : public std::iterator + : public std::iterator< + std::forward_iterator_tag, const T> { private: RangeIterData data; @@ -191,7 +192,7 @@ namespace iter { is_end{in_is_end} { } - T operator*() const { + const T& operator*() const { return this->data.value(); } From f14b4051a1cc81d50b566670de2d8689f601cd85 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 26 May 2015 11:36:43 -0700 Subject: [PATCH 1136/1866] ignores catch.hpp --- test/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/test/.gitignore b/test/.gitignore index 68c1db22..b08f9d55 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -5,3 +5,4 @@ test_* .sconsign.dblite config.log .sconf_temp/ +catch.hpp From 1209101060265fc848fab3a3fa681584e4d8b5a9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 26 May 2015 12:24:39 -0700 Subject: [PATCH 1137/1866] 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 1138/1866] 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 1139/1866] 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 dd6debf992c9fbcc4bbc40e63e4914f35a55960a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 29 May 2015 13:59:29 -0700 Subject: [PATCH 1140/1866] describes library behavior --- README.md | 114 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 89 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index e8895623..5c1c4540 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,22 @@ CPPItertools ============ -range-based for loop add-ons inspired by the Python builtins and itertools +Range-based for loop add-ons inspired by the Python builtins and itertools library. Like itertools and the Python3 builtins, this library uses lazy evaluation wherever possible. *Note*: Everthing is inside the `iter` namespace. -#### Requirements -This library is **header-only** and relies only on the C++ standard -library. The only exception is `zip_longest` which uses `boost::optional`. -`#include ` will include all of the provided -tools except for `zip_longest` which must be included separately. You may -also include individual pieces with the relevant header -(`#include ` for example). - #### Table of Contents [range](#range)
[enumerate](#enumerate)
[zip](#zip)
-[zip_longest](#zip)
+[zip\_longest](#zip)
[imap](#imap)
[filter](#filter)
[filterfalse](#filterfalse)
-[unique_everseen](#unique_everseen)
-[unique_justseen](#unique_justseen)
+[unique\_everseen](#unique_everseen)
+[unique\_justseen](#unique_justseen)
[takewhile](#takewhile)
[dropwhile](#dropwhile)
[cycle](#cycle)
@@ -38,20 +30,87 @@ also include individual pieces with the relevant header [chain.from\_iterable](#chainfrom_iterable)
[reversed](#reversed)
[slice](#slice)
-[sliding_window](#sliding_window)
+[sliding\_window](#sliding_window)
[grouper](#grouper)
##### Combinatoric fuctions [product](#product)
[combinations](#combinations)
-[combinations_with_replacement](#combinations_with_replacement)
+[combinations\_with\_replacement](#combinations_with_replacement)
[permutations](#permutations)
[powerset](#powerset)
+#### Requirements +This library is **header-only** and relies only on the C++ standard +library. The only exception is `zip_longest` which uses `boost::optional`. +`#include ` will include all of the provided +tools except for `zip_longest` which must be included separately. You may +also include individual pieces with the relevant header +(`#include ` for example). + +#### Requirements of passed objects +Most itertools will work with iterables using InputIterators and not copy +or move any underlying elements. The itertools that need ForwardIterators or +have additional requirements are noted in this document. However, the cases +should be fairly obvious: any time an element needs to appear multiple times +(as in `combinations` or `cycle`) or be looked at more than once (specifically, +`sorted`). +This library takes every effort to rely on as little as possible from the +underlying iterables, but if anything noteworthy is needed it is described +in this document. + +#### Feedback +If you find anything not working as you expect, not compiling when you believe +it should, a divergence from the python itertools behavior, or any sort of +error, please let me know. The preferable means would be to open an issue on +github. If you want to talk about an issue that you don't feel would be +appropriate as a github issue (or you just don't want to open one), +You can email me directly with whatever code you have that describes the +problem, I've been pretty responsive in the past. If I believe you are +"misusing" the library I'll try to put the blame on myself for being unclear +in this document and take the steps to clarify it. So please, contact me with +any concerns, I'm open to feedback. + +#### How (not) to use this library +The library functions create and return objects that are properly templated on +the iterable they are passed. These exact names of these types or +precisely how they are templated is unspecified, you should rely on the +functions described in this document. +If you plan to use these functions in very simple, straight forward means as in +the examples on this page, then you will be fine. If you feel like you need to +open the header files, then I've probably under-described something, let me +know. + +#### Handling of rvalues vs lvalues +The rules are pretty simple, and the library can be largely used without +knowledge of them. +Let's take an example +```c++ +std::vector vec{2,4,6,8}; +for (auto&& p : enumerate(vec)) { /* ... */ } +``` +In this case, `enumerate` will return an object that has bound a reference to +`vec`. No copies are produced here, neither of `vec` nor of the elements it +holds. + +If an rvalue was passed to enumerate, binding a reference would be unsafe. +Consider: +```c++ +for (auto&& p : enumerate(std::vector{2,4,6,8})) { /* ... */ } +``` +Instead, `enumerate` will return an object that has the temporary *moved* into +it. That is, the returned object will contain a `std::vector` rather than +just a reference to one. This may seem like a contrived example, but it matters +when `enumerate` is passed the result of a function call like `enumerate(f())`, +or, more obviously, something like `enumerate(zip(a, b))`. The object returned +from `zip` must be moved into the `enumerate` object. As a more specific +result, itertools can be mixed and nested. + + range ----- -Uses an underlying iterator to acheive the same effect of the python range +Uses an underlying iterator to achieve the same effect of the python range function. `range` can be used in three different ways: Only the stopping point is provided. Prints `0 1 2 3 4 5 6 7 8 9` @@ -92,12 +151,17 @@ for(auto i : range(5.0, 10.0, 0.5)) { } ``` +*Implementation Note*: Typical ranges have their current value incremented by +the step size repeatedly (`value += step`). Floating point range value are +recomputed at each step to avoid accumulating floating point inaccuracies +(`value = start + (step * steps_taken`). The result of the latter is a bit +slower but more accurate. + enumerate --------- -Can be used with any class with an iterator. Continually "yields" containers -similar to pairs. They are basic structs with a .index and a .element. Usage -appears as: +Continually "yields" containers similar to pairs. They are basic structs with a +.index and a .element. Usage appears as: ```c++ vector vec{2, 4, 6, 8}; @@ -154,7 +218,7 @@ for(auto&& i : filterfalse(vec)) { } ``` -unique_everseen +unique\_everseen --------------- This is a filter adaptor that only generates values that have never been seen before. For this to work your object must be specialized for `std::hash`. @@ -167,7 +231,7 @@ for (auto&& i : unique_everseen(v)) { } ``` -unique_justseen +unique\_justseen -------------- Another filter adaptor that only omits consecutive duplicates. @@ -319,7 +383,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++ @@ -337,7 +401,7 @@ for (auto&& e : zip(i,f,s,d)) { } ``` -zip_longest +zip\_longest ----------- Terminates on the longest sequence instead of the shortest. Repeatedly yields a tuple of `boost::optional`s where `T` is the type @@ -457,7 +521,7 @@ for (auto&& i : chain(empty,vec1,arr1)) { } ``` -chain.from_iterable +chain.from\_iterable ------------------- Similar to chain, but rather than taking a variadic number of iterables, @@ -501,7 +565,7 @@ for (auto&& i : slice(a,0,15,3)) { } ``` -sliding_window +sliding\_window ------------- Takes a section from a range and increments the whole section. @@ -583,7 +647,7 @@ for (auto&& i : combinations(v,3)) { } ``` -combinations_with_replacement +combinations\_with\_replacement ----------------------------- Like combinations, but with replacement of each element. The below is printed by the loop that follows: From 2131e2d967e8e4c9729ab9c70d411393877dc8ee Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 29 May 2015 14:05:51 -0700 Subject: [PATCH 1141/1866] adds forward iterator test checking persistence --- test/test_range.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/test_range.cpp b/test/test_range.cpp index 11c651c8..6af09277 100644 --- a/test/test_range.cpp +++ b/test/test_range.cpp @@ -161,6 +161,11 @@ TEST_CASE("range: forward iterator checks", "[range]") { REQUIRE( it3 == it2 ); auto it4 = ++it3; REQUIRE( it4 == it3 ); + + auto it5 = std::begin(r); + const auto& v = *it5; + ++it5; + REQUIRE( v != *it5 ); } TEST_CASE("range: forward iterator with double, checks", "[range]") { From a9ddd56bd43198a857b15389aa96e2e25b56e65f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 29 May 2015 14:06:22 -0700 Subject: [PATCH 1142/1866] range operator*() returns T instead of const T& this makes more sense. const auto& v= *it; ++it; // this shouldn't change v --- range.hpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/range.hpp b/range.hpp index 0bfd5051..8ac36aa9 100644 --- a/range.hpp +++ b/range.hpp @@ -38,7 +38,7 @@ namespace iter { step_{in_step} { } - const T& value() const { + T value() const { return this->value_; } @@ -75,7 +75,7 @@ namespace iter { step_{in_step} { } - const T& value() const { + T value() const { return this->value_; } @@ -144,9 +144,17 @@ namespace iter { { } public: + // the reference type here is T, which doesn't strictly follow all + // of the rules, but std::vector::iterator::reference isn't + // a reference type either, this isn't any worse + class Iterator : public std::iterator< - std::forward_iterator_tag, const T> + std::forward_iterator_tag, + T, + std::ptrdiff_t, + T*, + T> { private: RangeIterData data; @@ -192,7 +200,7 @@ namespace iter { is_end{in_is_end} { } - const T& operator*() const { + T operator*() const { return this->data.value(); } From 5dc24e107d3e0cf5c4311e69c0ac10e39b7805a7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 29 May 2015 15:13:51 -0700 Subject: [PATCH 1143/1866] corrects include guard name --- unique_justseen.hpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/unique_justseen.hpp b/unique_justseen.hpp index eaf81747..29d6362a 100644 --- a/unique_justseen.hpp +++ b/unique_justseen.hpp @@ -1,5 +1,5 @@ -#ifndef UNIQUE_JUSTSEEN_HPP -#define UNIQUE_JUSTSEEN_HPP +#ifndef ITER_UNIQUE_JUSTSEEN_HPP +#define ITER_UNIQUE_JUSTSEEN_HPP #include "iterbase.hpp" #include "groupby.hpp" @@ -9,7 +9,7 @@ #include #include -namespace iter +namespace iter { template struct GroupFrontGetter{ @@ -48,5 +48,4 @@ namespace iter } } -#endif //UNIQUE_JUSTSEEN_HPP - +#endif From 7d7e0d874978804a19c8e83b6128b718ef280b18 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 31 May 2015 15:25:23 -0700 Subject: [PATCH 1144/1866] adds arrow helper for aiding in determining the type of and calling operator-> --- iterbase.hpp | 66 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 13 deletions(-) diff --git a/iterbase.hpp b/iterbase.hpp index be7d71db..8715e320 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -16,6 +16,19 @@ #include namespace iter { + template + struct type_is { + using type = T; + }; + + // gcc CWG 1558 + template + struct void_t_help { + using type = void; + }; + template + using void_t = typename void_t_help::type; + // iterator_type is the type of C's iterator template @@ -51,6 +64,46 @@ namespace iter { using reverse_iterator_deref = decltype(*std::declval&>()); + namespace detail { + template + struct ArrowHelper { + using type = void; + }; + + template + struct ArrowHelper { + using type = T*; + constexpr type operator()(T* t) const noexcept { + return t; + } + }; + + + template + struct ArrowHelper().operator->())>> { + using type = decltype(std::declval().operator->()); + type operator()(T& t) const { + return t.operator->(); + } + }; + + template + using arrow = typename detail::ArrowHelper::type; + + } + + // type of C::iterator::operator->, also works with pointers + // void if the iterator has no operator-> + template + using iterator_arrow = arrow>; + + // applys the -> operator to an object, if the object is a pointer, + // it returns the pointer + template + arrow apply_arrow(T& t) { + return detail::ArrowHelper{}(t); + } + template struct is_random_access_iter : std::false_type { }; @@ -219,19 +272,6 @@ namespace iter { } }; - template - struct type_is { - using type = T; - }; - - // gcc CWG 1558 - template - struct void_t_help { - using type = void; - }; - template - using void_t = typename void_t_help::type; - } #endif From 853a4584f782ad44bbac2bf89d9724f590777aa6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 31 May 2015 15:26:06 -0700 Subject: [PATCH 1145/1866] tests cycle operator-> --- test/test_cycle.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/test_cycle.cpp b/test/test_cycle.cpp index 572e73d6..5b09ab25 100644 --- a/test/test_cycle.cpp +++ b/test/test_cycle.cpp @@ -56,3 +56,10 @@ TEST_CASE("cycle: iterator meets requirements", "[cycle]") { auto c = cycle(s); REQUIRE( itertest::IsIterator::value ); } + +TEST_CASE("cycle: arrow works", "[cycle]") { + std::vector v = {"hello"}; + auto c = cycle(v); + auto it = std::begin(c); + REQUIRE( it->size() == 5 ); +} From 6817b9502c960b673ec0f8125fcca5ab45771612 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 31 May 2015 15:26:18 -0700 Subject: [PATCH 1146/1866] adds operator-> to cycle iter --- cycle.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cycle.hpp b/cycle.hpp index 5745340b..42b86117 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -53,6 +53,10 @@ namespace iter { iterator_deref operator*() { return *this->sub_iter; } + + iterator_arrow operator->() { + return apply_arrow(this->sub_iter); + } Iterator& operator++() { ++this->sub_iter; From c1fbb50b25cc9b77335df5fdbeacdf58b4de4215 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 31 May 2015 21:10:42 -0700 Subject: [PATCH 1147/1866] adds detail:: on arrow --- iterbase.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iterbase.hpp b/iterbase.hpp index 8715e320..a5b80e51 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -95,12 +95,12 @@ namespace iter { // type of C::iterator::operator->, also works with pointers // void if the iterator has no operator-> template - using iterator_arrow = arrow>; + using iterator_arrow = detail::arrow>; // applys the -> operator to an object, if the object is a pointer, // it returns the pointer template - arrow apply_arrow(T& t) { + detail::arrow apply_arrow(T& t) { return detail::ArrowHelper{}(t); } From f703c943e17689620670d135d444b236c40a5198 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 31 May 2015 21:30:05 -0700 Subject: [PATCH 1148/1866] tests that iterators have arrow operators --- test/helpers.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/helpers.hpp b/test/helpers.hpp index 0be552b2..99cb404b 100644 --- a/test/helpers.hpp +++ b/test/helpers.hpp @@ -182,6 +182,7 @@ struct IsIterator ())), // copyctor decltype(std::declval() = std::declval()), // copy = decltype(*std::declval()), // operator* + decltype(std::declval().operator->()), // operator-> decltype(++std::declval()), // prefix ++ decltype(std::declval()++), // postfix ++ decltype(std::declval() != std::declval()), // != From bfaa56676d808abba1b5a75ac335a921e12230fe Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 31 May 2015 21:35:07 -0700 Subject: [PATCH 1149/1866] adds operator-> to accumulate --- accumulate.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/accumulate.hpp b/accumulate.hpp index e0dbb137..c7d4aa7c 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -76,6 +76,10 @@ namespace iter { return this->acc_val; } + const AccumVal* operator->() const { + return &this->acc_val; + } + Iterator& operator++() { ++this->sub_iter; if (this->sub_iter != this->sub_end) { From 30cd575c91dffdbec8e98735ed8b2570c06031cb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 31 May 2015 21:42:38 -0700 Subject: [PATCH 1150/1866] tests accumulate arrow gives correct result --- test/test_accumulate.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/test_accumulate.cpp b/test/test_accumulate.cpp index f8f2d3d7..00c9f469 100644 --- a/test/test_accumulate.cpp +++ b/test/test_accumulate.cpp @@ -63,6 +63,13 @@ TEST_CASE("accumulate: postfix ++", "[accumulate]") { REQUIRE( *it == 5 ); } +TEST_CASE("accumulate: operator->", "[accumulate]") { + Vec ns{7, 3}; + auto a = accumulate(ns); + auto it = std::begin(a); + const int *p = it.operator->(); + REQUIRE( *p == 7 ); +} TEST_CASE("accumulate: iterator meets requirements", "[accumulate]") { Vec ns{}; From b424251355c1bff43b5a02ee30ed13e50cfc451b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 31 May 2015 21:49:06 -0700 Subject: [PATCH 1151/1866] tests combinations arrow --- test/test_combinations.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/test_combinations.cpp b/test/test_combinations.cpp index dfdb0d0b..b01c2224 100644 --- a/test/test_combinations.cpp +++ b/test/test_combinations.cpp @@ -37,6 +37,14 @@ TEST_CASE("combinations: iterators can be compared", "[combinations]") { REQUIRE_FALSE( it == std::begin(c) ); } +TEST_CASE("combinations: operator->", "[combinations]") { + std::string s{"ABCD"}; + auto c = combinations(s, 2); + auto it = std::begin(c); + REQUIRE( it->size() == 2 ); +} + + TEST_CASE("combinations: size too large gives no results", "[combinations]") { std::string s{"ABCD"}; auto c = combinations(s, 5); From 83bceda958f291661d2bee129b1ec3d2a3c575b0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 31 May 2015 21:49:15 -0700 Subject: [PATCH 1152/1866] adds operator-> to combinations iter --- combinations.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/combinations.hpp b/combinations.hpp index a2cfeda2..fc70c6ee 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -77,6 +77,10 @@ namespace iter { return this->indices; } + CombIteratorDeref* operator->() { + return &this->indices; + } + Iterator& operator++() { for (auto iter = indices.get().rbegin(); From efb883c0a159be8055cd4185ef873ee5bf851055 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 31 May 2015 21:56:24 -0700 Subject: [PATCH 1153/1866] tests comb_w_repl -> --- test/test_combinations_with_replacement.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/test_combinations_with_replacement.cpp b/test/test_combinations_with_replacement.cpp index c58aec6d..e5e91f25 100644 --- a/test/test_combinations_with_replacement.cpp +++ b/test/test_combinations_with_replacement.cpp @@ -55,6 +55,14 @@ TEST_CASE("combinations_with_replacement: 0 size is empty", REQUIRE( std::begin(cwr) == std::end(cwr) ); } +TEST_CASE("combinations_with_replacement: operator->", + "[combinations_with_replacement]") { + std::string s{"ABCD"}; + auto c = combinations_with_replacement(s, 2); + auto it = std::begin(c); + REQUIRE( it->size() == 2 ); +} + TEST_CASE("combinations_with_replacement: binds to lvalues, moves rvalues", "[combinations_with_replacement]") { BasicIterable bi{'x', 'y', 'z'}; From a8295ea686dedf311f15006b0579514203fed463 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 31 May 2015 21:56:46 -0700 Subject: [PATCH 1154/1866] adds comb_w_repl iter -> --- combinations.hpp | 2 +- combinations_with_replacement.hpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/combinations.hpp b/combinations.hpp index fc70c6ee..2f52a7e5 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -77,7 +77,7 @@ namespace iter { return this->indices; } - CombIteratorDeref* operator->() { + CombIteratorDeref *operator->() { return &this->indices; } diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index 900e563e..0a1d11c6 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -70,6 +70,9 @@ namespace iter { return this->indices; } + CombIteratorDeref *operator->() { + return &this->indices; + } Iterator& operator++() { for (auto iter = indices.get().rbegin(); From b3ad7859161cae662918f894dafce7657a6e0dd0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 31 May 2015 22:00:13 -0700 Subject: [PATCH 1155/1866] tests compress operator-> --- test/test_compress.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/test_compress.cpp b/test/test_compress.cpp index 29a7c068..1152b60a 100644 --- a/test/test_compress.cpp +++ b/test/test_compress.cpp @@ -60,6 +60,15 @@ TEST_CASE("compress: all false", "[compress]") { REQUIRE( std::begin(c) == std::end(c) ); } +TEST_CASE("compress: operator->", "[compress") { + std::vector svec = {"a", "abc", "abcde"}; + std::vector bvec = {false, false, true}; + auto c = compress(svec, bvec); + auto it = std::begin(c); + REQUIRE( it->size() == 5 ); +} + + TEST_CASE("compress: binds to lvalues, moves rvalues", "[compress]") { BasicIterable bi{'x', 'y', 'z'}; std::vector bl{true, true, true}; From c6c62f66f887118f2564757d5be9c07aa1339f22 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 31 May 2015 22:00:24 -0700 Subject: [PATCH 1156/1866] adds compress iter -> --- compress.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compress.hpp b/compress.hpp index 404f3047..cc79b930 100644 --- a/compress.hpp +++ b/compress.hpp @@ -105,6 +105,10 @@ namespace iter { return *this->sub_iter; } + iterator_arrow operator->() { + return apply_arrow(this->sub_iter); + } + Iterator& operator++() { this->increment_iterators(); this->skip_failures(); From a65034a8fd8062ba5177fb2e2083a4b9f5f22547 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 1 Jun 2015 00:56:22 -0700 Subject: [PATCH 1157/1866] DerefHolder pull() behavior removed I totally misunderstood one of the InputIterator requirements. I guess that at some point I read "single-pass" and thought it meant you were only able to dereference the object one time. I have to update everything using pull() to use get() instead, which can be invoked more than once. --- iterbase.hpp | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/iterbase.hpp b/iterbase.hpp index be7d71db..f2dd287e 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -152,6 +152,9 @@ namespace iter { std::unique_ptr item_p; public: + using reference = TPlain&; + using pointer = TPlain*; + DerefHolder() = default; DerefHolder(const DerefHolder& other) @@ -168,14 +171,12 @@ namespace iter { DerefHolder& operator=(DerefHolder&&) = default; ~DerefHolder() = default; - TPlain& get() { - return *item_p; + reference get() { + return *this->item_p; } - T pull() { - // NOTE should I reset the unique_ptr to nullptr here - // since its held item is now invalid anyway? - return std::move(*item_p); + pointer get_ptr() { + return this->item_p.get(); } void reset(T&& item) { @@ -194,20 +195,22 @@ namespace iter { class DerefHolder::value>::type> { - private: - static_assert(std::is_lvalue_reference::value, - "lvalue specialization handling non-lvalue-ref type"); + public: + using reference = T; + using pointer = typename std::remove_reference::type*; - typename std::remove_reference::type *item_p =nullptr; + private: + pointer item_p{}; + public: DerefHolder() = default; - T get() { + reference get() { return *this->item_p; } - T pull() { - return this->get(); + pointer get_ptr() { + return this->item_p; } void reset(T item) { From cc49a1d8ae1a8966710d1c901aaf77947fd2d269 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 1 Jun 2015 00:59:26 -0700 Subject: [PATCH 1158/1866] uses get() instead of pull() --- filter.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/filter.hpp b/filter.hpp index 60a1be0d..11b4c65a 100644 --- a/filter.hpp +++ b/filter.hpp @@ -47,9 +47,10 @@ namespace iter { iterator_traits_deref> { protected: + using Holder = DerefHolder>; iterator_type sub_iter; iterator_type sub_end; - DerefHolder> item; + Holder item; FilterFunc *filter_func; void inc_sub_iter() { @@ -82,8 +83,8 @@ namespace iter { this->skip_failures(); } - iterator_deref operator*() { - return this->item.pull(); + typename Holder::reference operator*() { + return this->item.get(); } Iterator& operator++() { From 32644725ec42ba029517e18c08d704b42bfc48a9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 1 Jun 2015 01:03:43 -0700 Subject: [PATCH 1159/1866] dropwhile uses get() instead of pull() --- dropwhile.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index d5c9947f..b9f048a0 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -43,9 +43,10 @@ namespace iter { iterator_traits_deref> { private: + using Holder = DerefHolder>; iterator_type sub_iter; iterator_type sub_end; - DerefHolder> item; + Holder item; FilterFunc *filter_func; void inc_sub_iter() { @@ -77,8 +78,8 @@ namespace iter { this->skip_passes(); } - iterator_deref operator*() { - return this->item.pull(); + typename Holder::reference operator*() { + return this->item.get(); } Iterator& operator++() { From 4470e2e8445cf370211305dab9105054d04bf194 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 1 Jun 2015 01:05:06 -0700 Subject: [PATCH 1160/1866] takewhile uses get() instead of pull() --- takewhile.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/takewhile.hpp b/takewhile.hpp index 2c27c715..738502cf 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -46,9 +46,10 @@ namespace iter { iterator_traits_deref> { private: + using Holder = DerefHolder>; iterator_type sub_iter; iterator_type sub_end; - DerefHolder> item; + Holder item; FilterFunc *filter_func; void inc_sub_iter() { @@ -79,8 +80,8 @@ namespace iter { this->check_current(); } - iterator_deref operator*() { - return this->item.pull(); + typename Holder::reference operator*() { + return this->item.get(); } Iterator& operator++() { From 819d463cba7c53a8cde429b05089f8882beeb2cb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 1 Jun 2015 01:44:46 -0700 Subject: [PATCH 1161/1866] groupby uses get() instead of pull() --- groupby.hpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index 488c93f3..5b4c316a 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -60,9 +60,10 @@ namespace iter { : public std::iterator { private: + using Holder = DerefHolder>; iterator_type sub_iter; iterator_type sub_end; - DerefHolder> item; + Holder item; KeyFunc *key_func; public: @@ -79,7 +80,6 @@ namespace iter { } KeyGroupPair operator*() { - // FIXME double deref return { (*this->key_func)(this->item.get()), Group{*this, (*this->key_func)(this->item.get())} @@ -117,11 +117,10 @@ namespace iter { return !(this->sub_iter != this->sub_end); } - iterator_deref pull() { - return this->item.pull(); + typename Holder::reference get() { + return this->item.get(); } - // FIXME double deref. Two deref holders? key_func_ret next_key() { return (*this->key_func)(this->item.get()); } @@ -218,7 +217,7 @@ namespace iter { } iterator_deref operator*() { - return this->group_p->owner.pull(); + return this->group_p->owner.get(); } }; From 85be4d2d66edf23f681b76422c1ce7675026c945 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 1 Jun 2015 01:45:57 -0700 Subject: [PATCH 1162/1866] updates DerefHolder comments --- iterbase.hpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/iterbase.hpp b/iterbase.hpp index f2dd287e..e0cbef61 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -135,11 +135,9 @@ namespace iter { // if the iterate dereferences to an lvalue references, a pointer to the // element is stored // if it does not, a value is stored instead - // get() returns a reference to the held item in either case - // pull() should be used when the item is being "pulled out" of the - // DerefHolder. after pull() is called, neither it nor get() can be - // safely called after - // reset() replaces the currently held item and may be called after pull() + // get() returns a reference to the held item + // get_ptr() returns a pointer to the held item + // reset() replaces the currently held item template class DerefHolder { From ded97106cafd4a232425595458d129ca64c2a94e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 1 Jun 2015 23:42:05 -0700 Subject: [PATCH 1163/1866] tests dropwhile operator-> --- test/test_dropwhile.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/test_dropwhile.cpp b/test/test_dropwhile.cpp index 7a4d7dee..c0b1707d 100644 --- a/test/test_dropwhile.cpp +++ b/test/test_dropwhile.cpp @@ -49,6 +49,14 @@ TEST_CASE("dropwhile: only drops from beginning", "[dropwhile]") { REQUIRE( v == vc ); } +TEST_CASE("dropwhile: operator->", "[dropwhile]") { + std::vector vs = {"a", "ab", "abcdef", "abcdefghi"}; + auto d = dropwhile( + [](const std::string& str) { return str.size() < 3; }, vs); + auto it = std::begin(d); + REQUIRE( it->size() == 6 ); +} + namespace { int less_than_five(int i) { return i < 5; From 6c1a084a1a684385f6b0271b4ccbc55016f42ca3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 1 Jun 2015 23:42:17 -0700 Subject: [PATCH 1164/1866] adds dropwhile iter -> --- dropwhile.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dropwhile.hpp b/dropwhile.hpp index b9f048a0..7cdece67 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -82,6 +82,10 @@ namespace iter { return this->item.get(); } + typename Holder::pointer operator->() { + return this->item.get_ptr(); + } + Iterator& operator++() { this->inc_sub_iter(); return *this; From c799257bfb737467b200f89b8b3f3c6ed051bf2c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 2 Jun 2015 01:09:39 -0700 Subject: [PATCH 1165/1866] adds arrow proxy to provide -> interface --- iterbase.hpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/iterbase.hpp b/iterbase.hpp index 15541bc9..3baf7ba7 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -104,6 +104,24 @@ namespace iter { return detail::ArrowHelper{}(t); } + // For iterators that have an operator* which returns a value + // they can return this type from their operator-> instead, which will + // wrap an object and allow it to be used with arrow + template + class ArrowProxy { + private: + T obj; + public: + ArrowProxy(T&& in_obj) + : obj(std::move(in_obj)) + { } + + T *operator->() { + return &obj; + } + }; + + template struct is_random_access_iter : std::false_type { }; From 3b7687a990d16978c328dacf7c19b94513e5bc2b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 2 Jun 2015 01:10:11 -0700 Subject: [PATCH 1166/1866] tests enumerate arrow --- test/test_enumerate.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/test_enumerate.cpp b/test/test_enumerate.cpp index 1a899bc2..3f315d3e 100644 --- a/test/test_enumerate.cpp +++ b/test/test_enumerate.cpp @@ -100,6 +100,14 @@ TEST_CASE("moves rvalues into enumerable object", "[enumerate]") { (void)e; } +TEST_CASE("enumerate: operator->", "[enumerate]") { + std::vector ns = {50, 60, 70}; + auto e = enumerate(ns); + auto it = std::begin(e); + REQUIRE( it->first == 0 ); + REQUIRE( it->second == 50 ); +} + TEST_CASE("Works with const iterable", "[enumerate]") { const std::string s{"ace"}; auto e = enumerate(s); From d8b29f6a402dbaeb7c3d106fae5c7683964d4f55 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 2 Jun 2015 01:10:27 -0700 Subject: [PATCH 1167/1866] adds enumerate iter -> --- enumerate.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/enumerate.hpp b/enumerate.hpp index 2775232a..bb70755d 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -80,6 +80,10 @@ namespace iter { return {this->index, *this->sub_iter}; } + ArrowProxy operator->() { + return {**this}; + } + Iterator& operator++() { ++this->sub_iter; ++this->index; From 90a865919b5fae98e94c2f6d057213b01e99910c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 3 Jun 2015 01:27:59 -0700 Subject: [PATCH 1168/1866] tests filter arrow --- test/test_filter.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/test_filter.cpp b/test/test_filter.cpp index 28d597d3..650925f9 100644 --- a/test/test_filter.cpp +++ b/test/test_filter.cpp @@ -95,6 +95,14 @@ TEST_CASE("filter: binds to lvalues, moves rvales", "[filter]") { } +TEST_CASE("filter: operator->", "[filter]") { + std::vector vs = {"ab", "abc", "abcdef"}; + auto f = filter([](const std::string& str) {return str.size() > 4;}, vs); + auto it = std::begin(f); + REQUIRE( it->size() == 6 ); +} + + TEST_CASE("filter: all elements fail predicate", "[filter]") { Vec ns{10,20,30,40,50}; auto f = filter(less_than_five, ns); From c8eb23d4c1e81a57f93046e213d67852ec6755ad Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 3 Jun 2015 01:28:16 -0700 Subject: [PATCH 1169/1866] adds filter iter -> --- filter.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/filter.hpp b/filter.hpp index 11b4c65a..12801ed3 100644 --- a/filter.hpp +++ b/filter.hpp @@ -87,6 +87,10 @@ namespace iter { return this->item.get(); } + typename Holder::pointer operator->() { + return this->item.get_ptr(); + } + Iterator& operator++() { this->inc_sub_iter(); this->skip_failures(); From d5a49e1f91f3ef0c15c66b546867b44c69f84d15 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Jun 2015 01:18:01 -0700 Subject: [PATCH 1170/1866] adds a bunch of groupby tests arrow correctness and copy-constructing GroupBy::Iterator --- test/test_groupby.cpp | 46 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/test/test_groupby.cpp b/test/test_groupby.cpp index 06139d7b..eddb2728 100644 --- a/test/test_groupby.cpp +++ b/test/test_groupby.cpp @@ -162,6 +162,52 @@ TEST_CASE("groupby: doesn't double dereference", "[groupby]") { } } +TEST_CASE("grouby: iterator doesn't need to be dereferenced before advanced", + "[groupby]") { + std::vector ns = {2, 4, 7}; + auto g = groupby(ns); + auto it = std::begin(g); + ++it; + REQUIRE( (*it).first == 4 ); +} + +TEST_CASE("groupby: iterator can be dereferenced multiple times", "[groupby]"){ + std::vector ns = {2, 4, 7}; + auto g = groupby(ns); + auto it = std::begin(g); + auto k1 = (*it).first; + auto k2 = (*it).first; + REQUIRE( k1 == k2 ); +} + + +TEST_CASE("groupby: copy constructed iterators behave as expected", + "[groupby]") { + std::vector ns = {2, 3, 4, 5}; + auto g = groupby(ns); + auto it = std::begin(g); + REQUIRE( it->first == 2 ); + { + auto it2 = it; + REQUIRE( it2->first == 2); + ++it; + REQUIRE( it->first == 3 ); + REQUIRE( *std::begin(it->second) == 3 ); + } + REQUIRE( it->first == 3 ); + REQUIRE( *std::begin(it->second) == 3 ); +} + + +TEST_CASE("groupby: operator-> on both iterator types", "[groupby]") { + std::vector ns = {"a", "abc"}; + auto g = groupby(ns, std::mem_fn(&std::string::size)); + auto it = std::begin(g); + REQUIRE( it->first == 1 ); + auto it2 = std::begin(it->second); + REQUIRE( it2->size() == 1 ); +} + TEST_CASE("groupby: iterator and groupiterator are correct", "[groupby]") { std::string s{"abc"}; auto c = groupby(s); From a943944ee453e1aa61166292ecc49f8ef1ac5cb5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 5 Jun 2015 01:18:37 -0700 Subject: [PATCH 1171/1866] adds groupby iter copy ctor and operator-> --- groupby.hpp | 66 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index 5b4c316a..e238373f 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -1,9 +1,12 @@ #ifndef ITER_GROUP_BY_HPP_ #define ITER_GROUP_BY_HPP_ +// this is easily the most functionally complex itertool + #include "iterbase.hpp" #include +#include #include #include #include @@ -54,18 +57,20 @@ namespace iter { private: using KeyGroupPair = std::pair; + using Holder = DerefHolder>; public: class Iterator : public std::iterator { private: - using Holder = DerefHolder>; iterator_type sub_iter; iterator_type sub_end; Holder item; KeyFunc *key_func; + std::unique_ptr current_key_group_pair; + public: Iterator(iterator_type&& si, iterator_type&& end, @@ -79,14 +84,43 @@ namespace iter { } } - KeyGroupPair operator*() { - return { - (*this->key_func)(this->item.get()), - Group{*this, (*this->key_func)(this->item.get())} - }; + Iterator(const Iterator& other) + : sub_iter{other.sub_iter}, + sub_end{other.sub_end}, + item{other.item}, + key_func{other.key_func} + { } + + Iterator& operator=(const Iterator& other) { + if (this == &other) return *this; + this->sub_iter = other.sub_iter; + this->sub_end = other.sub_end; + this->item = other.item; + this->key_func = other.key_func; + this->current_key_group_pair.reset(); + return *this; + } + + ~Iterator() =default; + + // NOTE the implicitly generated move constructor would + // be wrong + + KeyGroupPair& operator*() { + set_key_group_pair(); + return *this->current_key_group_pair; + } + + KeyGroupPair *operator->() { + set_key_group_pair(); + return this->current_key_group_pair.get(); } Iterator& operator++() { + if (!this->current_key_group_pair) { + this->set_key_group_pair(); + } + this->current_key_group_pair.reset(); return *this; } @@ -121,9 +155,23 @@ namespace iter { return this->item.get(); } + typename Holder::pointer get_ptr() { + return this->item.get_ptr(); + } + key_func_ret next_key() { return (*this->key_func)(this->item.get()); } + + void set_key_group_pair() { + if (!this->current_key_group_pair) { + this->current_key_group_pair.reset( + new KeyGroupPair( + (*this->key_func)(this->item.get()), + Group{*this, this->next_key()})); + } + } + }; @@ -162,7 +210,7 @@ namespace iter { // move-constructible, non-copy-constructible, // non-assignable Group() = delete; - Group(const Group&) = delete; + Group(const Group&) = default; Group& operator=(const Group&) = delete; Group& operator=(Group&&) = delete; @@ -219,6 +267,10 @@ namespace iter { iterator_deref operator*() { return this->group_p->owner.get(); } + + typename Holder::pointer operator->() { + return this->group_p->owner.get_ptr(); + } }; GroupIterator begin() { From e7746c33ecd16e03e37cf3b338790fb114283373 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Jun 2015 18:06:18 -0700 Subject: [PATCH 1172/1866] adds -> to grouper iter --- grouper.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/grouper.hpp b/grouper.hpp index c96a9f80..d3bebcdf 100644 --- a/grouper.hpp +++ b/grouper.hpp @@ -103,6 +103,10 @@ namespace iter { DerefVec& operator*() { return this->group; } + + DerefVec *operator->() { + return &this->group; + } }; Iterator begin() { From 4c9eaf958a0f6ac37446fa416b7477fb96210d03 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Jun 2015 18:24:39 -0700 Subject: [PATCH 1173/1866] tests imap iter -> --- test/test_imap.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/test_imap.cpp b/test/test_imap.cpp index 71a70440..6911c0fa 100644 --- a/test/test_imap.cpp +++ b/test/test_imap.cpp @@ -84,6 +84,22 @@ TEST_CASE("imap: terminates on shortest squence", "[imap]") { } } +TEST_CASE("imap: operator->", "[imap]") { + std::vector vs = {"ab", "abcd", "abcdefg"}; + { + auto m = imap([](std::string& s) { return s; }, vs); + auto it = std::begin(m); + REQUIRE( it->size() == 2 ); + } + + { + auto m = imap([](std::string& s) -> std::string& { return s; }, vs); + auto it = std::begin(m); + REQUIRE( it->size() == 2 ); + } +} + + TEST_CASE("imap: empty sequence gives nothing", "[imap]") { Vec v{}; auto im = imap(plusone, v); From ae1c891a347213c0954f628a6f23e3344f4014f6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Jun 2015 18:24:53 -0700 Subject: [PATCH 1174/1866] adds imap iter operator-> --- imap.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/imap.hpp b/imap.hpp index f4cf1279..cbe7174c 100644 --- a/imap.hpp +++ b/imap.hpp @@ -106,8 +106,8 @@ namespace iter { ZippedIterType zipiter; public: - Iterator(MapFunc& in_map_func, ZippedIterType&& in_zipiter) : - map_func(&in_map_func), + Iterator(MapFunc& in_map_func, ZippedIterType&& in_zipiter) + : map_func(&in_map_func), zipiter(std::move(in_zipiter)) { } @@ -116,6 +116,10 @@ namespace iter { *this->map_func, *(this->zipiter)); } + ArrowProxy operator->() { + return {**this}; + } + Iterator& operator++() { ++this->zipiter; return *this; From 271a41c21f4f505650991c26d8eca4ca24c530c2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Jun 2015 18:40:53 -0700 Subject: [PATCH 1175/1866] adds permutations iter -> --- permutations.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/permutations.hpp b/permutations.hpp index 547b6aef..4e53f259 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -57,7 +57,11 @@ namespace iter { } Permutable& operator*() { - return working_set; + return this->working_set; + } + + Permutable *operator->() { + return &this->working_set; } Iterator& operator++() { From 3d2d622b701e9ebcee809b54745ba9df2e500f41 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Jun 2015 18:44:07 -0700 Subject: [PATCH 1176/1866] adds powerset iter -> --- powerset.hpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/powerset.hpp b/powerset.hpp index 5635cc4e..a87b73f2 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -29,7 +29,8 @@ namespace iter { std::input_iterator_tag, CombinatorType> { private: - typename std::remove_reference::type *container_p; + typename std::remove_reference::type * + container_p; std::size_t set_size; std::shared_ptr comb; iterator_type comb_iter; @@ -39,7 +40,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{new CombinatorType( + combinations(in_container, sz))}, comb_iter{std::begin(*comb)}, comb_end{std::end(*comb)} { } @@ -49,7 +51,8 @@ namespace iter { if (this->comb_iter == this->comb_end) { ++this->set_size; this->comb.reset(new CombinatorType(combinations( - *this->container_p, this->set_size))); + *this->container_p, + this->set_size))); this->comb_iter = std::begin(*this->comb); this->comb_end = std::end(*this->comb); } @@ -66,6 +69,10 @@ namespace iter { return *this->comb_iter; } + iterator_arrow operator->() { + apply_arrow(this->comb_iter); + } + bool operator != (const Iterator& other) const { return !(*this == other); } From 5d85e4c99f4cf9a17d0641c818b8d17535aa62fe Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Jun 2015 18:49:10 -0700 Subject: [PATCH 1177/1866] adds product iter -> --- product.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/product.hpp b/product.hpp index 72ef1b36..c0c90858 100644 --- a/product.hpp +++ b/product.hpp @@ -98,6 +98,10 @@ namespace iter { *this->iter}, *this->rest_iter); } + + ArrowProxy operator->() { + return {**this}; + } }; Iterator begin() { From 180b87dda6f29cd4a292cc18ce2277f0768eaa5f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Jun 2015 18:53:24 -0700 Subject: [PATCH 1178/1866] adds range iter -> though this doesn't make sense without a custom larger numeric type --- range.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/range.hpp b/range.hpp index 8ac36aa9..abfed9ba 100644 --- a/range.hpp +++ b/range.hpp @@ -204,6 +204,12 @@ namespace iter { return this->data.value(); } +#if 0 + ArrowProxy operator->() const { + return {**this}; + } +#endif + Iterator& operator++() { this->data.inc(); return *this; From 41ffc5e8bc7f62f7176a77eeac1bf0626ef91faf Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Jun 2015 18:54:12 -0700 Subject: [PATCH 1179/1866] ArrowProxy can handle references as well --- iterbase.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iterbase.hpp b/iterbase.hpp index 3baf7ba7..1144c1ea 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -110,13 +110,14 @@ namespace iter { template class ArrowProxy { private: + using TPlain = typename std::remove_reference::type; T obj; public: ArrowProxy(T&& in_obj) - : obj(std::move(in_obj)) + : obj(std::forward(in_obj)) { } - T *operator->() { + TPlain *operator->() { return &obj; } }; From 421699dcdabf84c0795e4c23bbf054b8658f68f5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Jun 2015 18:55:52 -0700 Subject: [PATCH 1180/1866] adds repeat iter -> --- repeat.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/repeat.hpp b/repeat.hpp index 03ecadce..5f3f8ccf 100644 --- a/repeat.hpp +++ b/repeat.hpp @@ -74,6 +74,10 @@ namespace iter { T& operator*() { return *this->elem; } + + TPlain* operator->() { + return this->elem; + } }; Iterator begin() { From e19fb8ab96d6e7c83eb75c9616f2264141793761 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Jun 2015 18:59:11 -0700 Subject: [PATCH 1181/1866] tests reversed iterator with array --- test/test_reversed.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test_reversed.cpp b/test/test_reversed.cpp index 389badd0..cade9326 100644 --- a/test/test_reversed.cpp +++ b/test/test_reversed.cpp @@ -65,4 +65,8 @@ TEST_CASE("reversed: iterator meets requirements", "[reversed]") { Vec v; auto r = reversed(v); REQUIRE( itertest::IsIterator::value ); + + int a[1]; + auto ra = reversed(a); + REQUIRE( itertest::IsIterator::value ); } From 3b2bde08d21dc9706996be3f078673942da05675 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Jun 2015 18:59:27 -0700 Subject: [PATCH 1182/1866] adds reverse_iterator_arrow --- iterbase.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iterbase.hpp b/iterbase.hpp index 1144c1ea..2d3a6b1e 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -97,6 +97,9 @@ namespace iter { template using iterator_arrow = detail::arrow>; + template + using reverse_iterator_arrow = detail::arrow>; + // applys the -> operator to an object, if the object is a pointer, // it returns the pointer template From 65a719856f695db1f654eaaecde5dfc4e07dddc7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Jun 2015 19:01:54 -0700 Subject: [PATCH 1183/1866] adds reversed iter -> and shortens array types --- reversed.hpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/reversed.hpp b/reversed.hpp index 0e03b6c1..795cb7ea 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -40,6 +40,10 @@ namespace iter { return *this->sub_iter; } + reverse_iterator_arrow operator->() { + return apply_arrow(this->sub_iter); + } + Iterator& operator++() { ++this->sub_iter; return *this; @@ -103,10 +107,14 @@ namespace iter { : sub_iter{iter} { } - iterator_deref operator*() { + T& operator*() { return *(this->sub_iter - 1); } + T *operator->() { + return (this->sub_iter - 1); + } + Iterator& operator++() { --this->sub_iter; return *this; From cf48d1a3f87eb8a93402b4644ca7e47e5dc56462 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Jun 2015 19:03:53 -0700 Subject: [PATCH 1184/1866] adds slice iter -> --- slice.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/slice.hpp b/slice.hpp index 2dfac39d..c97dfc0b 100644 --- a/slice.hpp +++ b/slice.hpp @@ -70,6 +70,10 @@ namespace iter { return *this->sub_iter; } + iterator_arrow operator->() { + return apply_arrow(this->sub_iter); + } + Iterator& operator++() { dumb_advance(this->sub_iter, this->sub_end,this->step); this->current += this->step; From 0e5774026d18d33359ce934cc70e0becbc3f68a0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Jun 2015 19:08:01 -0700 Subject: [PATCH 1185/1866] makes Slice class constructor private --- slice.hpp | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/slice.hpp b/slice.hpp index c97dfc0b..1880522d 100644 --- a/slice.hpp +++ b/slice.hpp @@ -10,15 +10,27 @@ namespace iter { - //Forward declarations of Slice and slice - //template - //class Slice; + template + class Slice; + + template + Slice slice( + Container&& container, + DifferenceType start, DifferenceType stop, DifferenceType step=1); + + template + Slice slice( + Container&& container, DifferenceType stop); + + template + Slice, DifferenceType> slice( + std::initializer_list il, DifferenceType start, + DifferenceType stop, DifferenceType step=1); - //template - //Slice> slice( std::initializer_list); + template + Slice, DifferenceType> slice( + std::initializer_list il, DifferenceType stop); - //template - //Slice slice(Container &&); template class Slice { private: @@ -27,12 +39,13 @@ namespace iter { DifferenceType stop; DifferenceType step; - // The only thing allowed to directly instantiate an Slice is - // the slice function - //friend Slice slice(Container &&); - //template - //friend Slice> slice(std::initializer_list); - public: + friend Slice slice( + Container&&, DifferenceType, DifferenceType, + DifferenceType); + + friend Slice slice( + Container&&, DifferenceType); + Slice(Container&& in_container, DifferenceType in_start, DifferenceType in_stop, DifferenceType in_step) : container(std::forward(in_container)), @@ -42,6 +55,7 @@ namespace iter { { } + public: class Iterator : public std::iterator> @@ -117,7 +131,7 @@ namespace iter { template Slice slice( Container&& container, - DifferenceType start, DifferenceType stop, DifferenceType step=1) { + DifferenceType start, DifferenceType stop, DifferenceType step) { return {std::forward(container), start, stop, step}; } @@ -131,7 +145,7 @@ namespace iter { template Slice, DifferenceType> slice( std::initializer_list il, DifferenceType start, - DifferenceType stop, DifferenceType step=1) { + DifferenceType stop, DifferenceType step) { return {std::move(il), start, stop, step}; } From d0258b78a8d8619d888c48af999c4029b2c88765 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Jun 2015 19:11:56 -0700 Subject: [PATCH 1186/1866] adds sliding_window iter -> --- sliding_window.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sliding_window.hpp b/sliding_window.hpp index 8d3526e0..36ab877e 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -74,6 +74,10 @@ namespace iter { return this->window; } + DerefVec *operator->() { + return this->window; + } + Iterator& operator++() { ++this->sub_iter; this->window.get().pop_front(); From daaa8b653e9d3ff56fb35ffdad49180980d48aa7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Jun 2015 19:14:27 -0700 Subject: [PATCH 1187/1866] *actually* adds range iter -> --- range.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/range.hpp b/range.hpp index abfed9ba..290d743c 100644 --- a/range.hpp +++ b/range.hpp @@ -15,6 +15,8 @@ // // If a step of 0 is provided, a RangeException will be thrown +#include "iterbase.hpp" + #include #include #include @@ -204,11 +206,9 @@ namespace iter { return this->data.value(); } -#if 0 ArrowProxy operator->() const { return {**this}; } -#endif Iterator& operator++() { this->data.inc(); From 8a503f74f675d15010af9c766072e9b171780415 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Jun 2015 19:14:55 -0700 Subject: [PATCH 1188/1866] adds takewhile iter -> --- takewhile.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/takewhile.hpp b/takewhile.hpp index 738502cf..6d514327 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -84,6 +84,10 @@ namespace iter { return this->item.get(); } + typename Holder::pointer operator->() { + return this->item.get_ptr(); + } + Iterator& operator++() { this->inc_sub_iter(); this->check_current(); From 38b3f70275de09df509b2641ef9113af85ee6596 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Jun 2015 19:25:30 -0700 Subject: [PATCH 1189/1866] adjusts unique_justseen for new groupby --- unique_justseen.hpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/unique_justseen.hpp b/unique_justseen.hpp index 29d6362a..3eb39cc2 100644 --- a/unique_justseen.hpp +++ b/unique_justseen.hpp @@ -8,17 +8,13 @@ #include #include #include +#include namespace iter { template struct GroupFrontGetter{ - auto operator()(iterator_deref&& gb) -> - decltype(*std::begin(gb.second)) { - return *std::begin(gb.second); - } - - auto operator()(iterator_deref& gb) -> + auto operator()(iterator_deref gb) -> decltype(*std::begin(gb.second)) { return *std::begin(gb.second); } From 4e5713e3fac003a01701bf3ddcd37bd515fa4a88 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Jun 2015 19:30:05 -0700 Subject: [PATCH 1190/1866] adds zip iter -> --- zip.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/zip.hpp b/zip.hpp index ca3ed78b..59171e48 100644 --- a/zip.hpp +++ b/zip.hpp @@ -86,6 +86,11 @@ namespace iter { *this->iter}, *this->rest_iter); } + + auto operator->() -> ArrowProxy { + return {**this}; + } + }; Iterator begin() { @@ -137,6 +142,10 @@ namespace iter { std::tuple<> operator*() { return std::tuple<>{}; } + + auto operator->() -> ArrowProxy { + return {**this}; + } }; Iterator begin() { From f81597aca53d7512cf3efcd11a562cc6c509a023 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Jun 2015 19:33:06 -0700 Subject: [PATCH 1191/1866] adds zip_longest iter -> --- zip_longest.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/zip_longest.hpp b/zip_longest.hpp index d1cc3e0f..937602df 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -99,6 +99,11 @@ namespace iter { *this->rest_iter); } } + + ArrowProxy operator->() { + return {**this}; + } + }; Iterator begin() { @@ -141,6 +146,10 @@ namespace iter { constexpr std::tuple<> operator*() const { return {}; } + + constexpr ArrowProxy> operator->() const { + return {{}}; + } }; constexpr Iterator begin() const { From 2a6468c98c3f4cd5a7dc12488e548b567357e4b3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Jun 2015 19:35:20 -0700 Subject: [PATCH 1192/1866] adds operator-> to ValidIter (for test_helpers) --- test/test_helpers.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_helpers.cpp b/test/test_helpers.cpp index 22d0a858..129a17d2 100644 --- a/test/test_helpers.cpp +++ b/test/test_helpers.cpp @@ -17,6 +17,7 @@ class ValidIter { bool operator==(const ValidIter&) const; bool operator!=(const ValidIter&) const; int operator*(); + void* operator->(); }; } From dda0c1912d0104e2dbcc4da3a00abb9e28a4a02a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Jun 2015 19:40:55 -0700 Subject: [PATCH 1193/1866] corrects chain.from_iterable Iter reqs test --- test/test_chain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_chain.cpp b/test/test_chain.cpp index c2a00fb0..46319d33 100644 --- a/test/test_chain.cpp +++ b/test/test_chain.cpp @@ -210,6 +210,6 @@ TEST_CASE("chain.from_iterable: empty", "[chain.from_iterable]") { TEST_CASE("chain.from_iterable: iterator meets requirements", "[chain.from_iterable]") { const std::vector v{}; - auto c = chain(v); + auto c = chain.from_iterable(v); REQUIRE( itertest::IsIterator::value ); } From d5062d8a5fe33bcd1d845407dad10e72cea9dd2c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Jun 2015 19:41:23 -0700 Subject: [PATCH 1194/1866] adds chain operator-> --- chain.hpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/chain.hpp b/chain.hpp index 65e15a36..f150bd18 100644 --- a/chain.hpp +++ b/chain.hpp @@ -90,6 +90,13 @@ namespace iter { return this->at_end ? *this->rest_iter : *this->sub_iter; } + + iterator_arrow operator->() { + return this->at_end ? + apply_arrow(this->rest_iter) + : apply_arrow(this->sub_iter); + } + }; Iterator begin() { @@ -155,6 +162,10 @@ namespace iter { iterator_deref operator*() { return *this->sub_iter; } + + iterator_arrow operator->() { + return apply_arrow(this->sub_iter); + } }; Iterator begin() { From 155865e694796c010c385b27bfea0b49e540fbbb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Jun 2015 19:42:43 -0700 Subject: [PATCH 1195/1866] adds chain.from_iterable iter -> --- chain.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/chain.hpp b/chain.hpp index f150bd18..1db17ad0 100644 --- a/chain.hpp +++ b/chain.hpp @@ -292,6 +292,10 @@ namespace iter { iterator_deref> operator*() { return **this->sub_iter_p; } + + iterator_arrow> operator->() { + return apply_arrow(*this->sub_iter_p); + } }; Iterator begin() { From a16a48b6d41e9d4c71f45ddac43f7d4621970974 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 19 Jun 2015 11:06:24 -0700 Subject: [PATCH 1196/1866] adds docs on who needs ForwardIterators --- README.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5c1c4540..efc92891 100644 --- a/README.md +++ b/README.md @@ -272,6 +272,8 @@ for (auto&& i : dropwhile([] (int i) {return i < 5;}, ivec)) { cycle ----- +*Additional Requirements*: Input must have a ForwardIterator + Repeatedly produces all values of an iterable. The loop will be infinite, so a `break` or other control flow structure is necessary to exit. @@ -487,6 +489,8 @@ for (auto&& i : compress(ivec, bvec) { sorted ------ +*Additional Requirements*: Input must have a ForwardIterator + Allows iteration over a sequence in sorted order. `sorted` does **not** produce a new sequence, copy elements, or modify the original sequence. It only provides a way to iterate over existing elements. @@ -507,6 +511,8 @@ for (auto&& i : sorted(nums)) { chain ----- +*Additional Requirements*: The underlying iterators of all containers' +`operator*` must have the *exact* same type This can chain any set of ranges together as long as their iterators dereference to the same type. @@ -567,7 +573,11 @@ for (auto&& i : slice(a,0,15,3)) { sliding\_window ------------- -Takes a section from a range and increments the whole section. +*Additional Requirements*: Input must have a ForwardIterator + +Takes a section from a range and increments the whole section. If the +window size is larger than the length of the input, the `sliding_window` will +yield nothing (begin == end). Example: `[1, 2, 3, 4, 5, 6, 7, 8, 9]` @@ -616,6 +626,7 @@ for (auto&& sec : grouper(v,4)) product ------ +*Additional Requirements*: Input must have a ForwardIterator Generates the cartesian project of the given ranges put together @@ -635,6 +646,7 @@ for (auto&& t : product(v1,v2,v3,v4)) { combinations ----------- +*Additional Requirements*: Input must have a ForwardIterator Generates n length unique sequences of the input range. @@ -649,6 +661,8 @@ for (auto&& i : combinations(v,3)) { combinations\_with\_replacement ----------------------------- +*Additional Requirements*: Input must have a ForwardIterator + Like combinations, but with replacement of each element. The below is printed by the loop that follows: ``` @@ -668,6 +682,7 @@ for (auto&& v : combinations_with_replacement(s, 2)) { permutations ----------- +*Additional Requirements*: Input must have a ForwardIterator Generates all the permutations of a range using `std::next_permutation`. The iterators of the sequence passed must have an `operator*() const` @@ -685,6 +700,7 @@ for (auto&& vec : permutations(v)) { powerset ------- +*Additional Requirements*: Input must have a ForwardIterator Generates every possible subset of a set, runs in O(2^n). From cb403144d3cbdb89760fac2fda8c3e5bfbdb1bb2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 19 Jun 2015 11:09:41 -0700 Subject: [PATCH 1197/1866] removes doc'ing comments from enumerate --- enumerate.hpp | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 2775232a..a190fb7d 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -9,16 +9,6 @@ #include #include - -// enumerate functionality for python-style for-each enumerate loops -// for (auto e : enumerate(vec)) { -// std::cout << e.index -// << ": " -// << e.element -// << '\n'; -// } - - namespace iter { //Forward declarations of Enumerable and enumerate @@ -50,9 +40,9 @@ namespace iter { Enumerable(Container&& in_container) : container(std::forward(in_container)) { } - + public: - // "yielded" by the Enumerable::Iterator. Has a .index, and a + // "yielded" by the Enumerable::Iterator. Has a .index, and a // .element referencing the value yielded by the subiterator class IterYield : public BasePair { public: @@ -74,13 +64,13 @@ namespace iter { Iterator(iterator_type&& si) : sub_iter{std::move(si)}, index{0} - { } + { } IterYield operator*() { return {this->index, *this->sub_iter}; } - Iterator& operator++() { + Iterator& operator++() { ++this->sub_iter; ++this->index; return *this; @@ -116,11 +106,10 @@ namespace iter { return {std::forward(container)}; } - // for initializer lists. copy constructs the list into the Enumerable template Enumerable> enumerate( std::initializer_list il) - { + { return {std::move(il)}; } } From af8bc59055eb09ef756428ce6dafb1c00f89e956 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 21 Jun 2015 11:10:44 -0700 Subject: [PATCH 1198/1866] marks ArrowProxy constructor constexpr --- iterbase.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iterbase.hpp b/iterbase.hpp index 2d3a6b1e..cc195a0e 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -116,7 +116,7 @@ namespace iter { using TPlain = typename std::remove_reference::type; T obj; public: - ArrowProxy(T&& in_obj) + constexpr ArrowProxy(T&& in_obj) : obj(std::forward(in_obj)) { } From 83c72a2687775547a60d6ef9b110a670d0ccf72c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 25 Jun 2015 22:26:44 -0700 Subject: [PATCH 1199/1866] accumulate doesn't default construct intermediate --- accumulate.hpp | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index c7d4aa7c..0a82ff46 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace iter { @@ -42,9 +43,6 @@ namespace iter { typename std::result_of, iterator_deref)>::type>::type; - static_assert( - std::is_default_constructible::value, - "Cannot accumulate a non-default constructible type"); Accumulator(Container&& in_container, AccumulateFunc in_accumulate_func) @@ -60,31 +58,52 @@ namespace iter { iterator_type sub_iter; iterator_type sub_end; AccumulateFunc accumulate_func; - AccumVal acc_val; + std::unique_ptr acc_val; public: - Iterator (iterator_type&& iter, + Iterator(iterator_type&& iter, iterator_type&& end, AccumulateFunc in_accumulate_func) : sub_iter{std::move(iter)}, sub_end{std::move(end)}, accumulate_func(in_accumulate_func), // only get first value if not an end iterator - acc_val(!(iter != end) ? AccumVal{} : *iter) + acc_val{!(iter != end) ? nullptr : new AccumVal(*iter)} { } + Iterator(const Iterator& other) + : sub_iter{other.sub_iter}, + sub_end{other.sub_end}, + accumulate_func{other.accumulate_func}, + acc_val{other.acc_val ? + new AccumVal(*other.acc_val) : nullptr} + { } + + Iterator& operator=(const Iterator& other) { + if (this == &other) return *this; + this->sub_iter = other.sub_iter; + this->sub_end = other.sub_end; + this->accumulate_func = other.accumulate_func; + this->acc_val.reset(other.acc_val ? + new AccumVal(*other.acc_val) : nullptr); + return *this; + } + + Iterator(Iterator&&) =default; + Iterator& operator=(Iterator&&) =default; + const AccumVal& operator*() const { - return this->acc_val; + return *this->acc_val; } const AccumVal* operator->() const { - return &this->acc_val; + return this->acc_val.get(); } Iterator& operator++() { ++this->sub_iter; if (this->sub_iter != this->sub_end) { - this->acc_val = accumulate_func( - this->acc_val, *this->sub_iter); + *this->acc_val = accumulate_func( + *this->acc_val, *this->sub_iter); } return *this; } From 116e6d5ab37e8e22707f0203556d89a4aa81b0dc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 25 Jun 2015 22:27:51 -0700 Subject: [PATCH 1200/1866] tests accumulate with lambda iters are assignable --- test/test_accumulate.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/test/test_accumulate.cpp b/test/test_accumulate.cpp index 00c9f469..1a4e9413 100644 --- a/test/test_accumulate.cpp +++ b/test/test_accumulate.cpp @@ -37,6 +37,21 @@ TEST_CASE("accumulate: with initializer_list works", "[accumulate]") { REQUIRE( v == vc ); } +struct Integer { + const int value; + constexpr Integer(int i) : value{i} { } + constexpr Integer operator+(Integer other) const noexcept { + return {this->value + other.value}; + } +}; + +TEST_CASE("accumulate: intermidate type need not be default constructible", + "[accumulate]") { + std::vector v = {{2}, {3}, {10}}; + auto a = accumulate(v, std::plus{}); + auto it = std::begin(a); +} + TEST_CASE("accumulate: binds reference when it should", "[accumulate]") { BasicIterable bi{1, 2}; accumulate(bi); @@ -73,6 +88,8 @@ TEST_CASE("accumulate: operator->", "[accumulate]") { TEST_CASE("accumulate: iterator meets requirements", "[accumulate]") { Vec ns{}; - auto a = accumulate(ns); + auto a = accumulate(ns, [](int a, int b) { return a + b; }); + auto it = std::begin(a); + it = std::begin(a); REQUIRE( itertest::IsIterator::value ); } From cd477bf3cc7a4c132cbc0b00e818a6859196fa7d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 25 Jun 2015 22:28:29 -0700 Subject: [PATCH 1201/1866] makes accumulate iters with lambda assignable --- accumulate.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index 0a82ff46..bc006abf 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -57,7 +57,7 @@ namespace iter { private: iterator_type sub_iter; iterator_type sub_end; - AccumulateFunc accumulate_func; + AccumulateFunc *accumulate_func; std::unique_ptr acc_val; public: Iterator(iterator_type&& iter, @@ -65,7 +65,7 @@ namespace iter { AccumulateFunc in_accumulate_func) : sub_iter{std::move(iter)}, sub_end{std::move(end)}, - accumulate_func(in_accumulate_func), + accumulate_func(&in_accumulate_func), // only get first value if not an end iterator acc_val{!(iter != end) ? nullptr : new AccumVal(*iter)} { } @@ -102,7 +102,7 @@ namespace iter { Iterator& operator++() { ++this->sub_iter; if (this->sub_iter != this->sub_end) { - *this->acc_val = accumulate_func( + *this->acc_val = (*accumulate_func)( *this->acc_val, *this->sub_iter); } return *this; From ca9e87db48cfce758f0305364997e056ee8c530e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 29 Jun 2015 21:00:32 -0700 Subject: [PATCH 1202/1866] changes range to have an empty range when step=0 this seems like the best choice if I'm not gonna throw, and I'd prefer not to throw, it seems heavyweight for the problem. I doubt this will be a real issue anyway. I can't personally remember ever needing to deal with a step of 0 in python in any way, I had to go see how it behaved when I originally wrote this range, actually. --- test/test_range.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/test_range.cpp b/test/test_range.cpp index 6af09277..daaed8a5 100644 --- a/test/test_range.cpp +++ b/test/test_range.cpp @@ -89,8 +89,11 @@ TEST_CASE("range: stops short when step > stop-start", "[range]") { REQUIRE( v.size() == 1 ); } -TEST_CASE("No 0 step ranges allowed", "[range]") { - REQUIRE_THROWS(range(0, 1, 0)); +TEST_CASE("Step size of 0 gives an empty range", "[range]") { + auto r = range(0, 10, 0); + REQUIRE( std::begin(r) == std::end(r) ); + auto r2 = range(0, -10, 0); + REQUIRE( std::begin(r2) == std::end(r2) ); } TEST_CASE("range: works with a variable start, stop, and step", "[range]") { From 05c9a4fe288778dea4004d9b48e87e0555dff07a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 29 Jun 2015 21:03:45 -0700 Subject: [PATCH 1203/1866] modifies range to meet the new test --- range.hpp | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/range.hpp b/range.hpp index 290d743c..289ef52c 100644 --- a/range.hpp +++ b/range.hpp @@ -1,20 +1,6 @@ #ifndef ITER_RANGE_H_ #define ITER_RANGE_H_ -// range() for range-based loops with start, stop, and step. -// -// Acceptable forms are: -// for (auto i : range(stop)) { ... } // start = 0, step = 1 -// for (auto i : range(start, stop)) { ... } // step = 1 -// for (auto i : range(start, stop, step)) { ... } -// -// The start may be greater than the stop if the range is negative -// The range will effectively be empty if: -// 1) step is positive and start > stop -// 2) step is negative and start < stop -// -// If a step of 0 is provided, a RangeException will be thrown - #include "iterbase.hpp" #include @@ -105,13 +91,6 @@ namespace iter { }; - // Thrown when step 0 occurs - class RangeException : public std::exception { - const char *what() const noexcept override { - return "range step must be non-zero"; - } - }; - template class Range; @@ -279,9 +258,7 @@ namespace iter { template Range range(T start, T stop, T step) { - if (step == 0) { - throw RangeException{}; - } + if (step == T(0)) return {0}; return {start, stop, step}; } } From c1445afc47c1acd0f5cb70ad582aedbb73954765 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 29 Jun 2015 21:04:00 -0700 Subject: [PATCH 1204/1866] documents range(x, y, 0) behavior --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index efc92891..02a6ba6e 100644 --- a/README.md +++ b/README.md @@ -141,6 +141,14 @@ for (auto i : range(2, -3, -1)) { } ``` +A step size of 0 results in an empty range (Python's raises an exception). +The following prints nothing +```c++ +for (auto i : range(0, 10, 0)) { + cout << i << '\n'; +} +``` + In addition to normal integer range operations, doubles and other numeric types are supported through the template From 47164c34c5d66892f44231a421964a88212498da Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 29 Jun 2015 21:10:21 -0700 Subject: [PATCH 1205/1866] tests that ranges can be created constexpr --- test/test_range.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/test_range.cpp b/test/test_range.cpp index daaed8a5..f9b29010 100644 --- a/test/test_range.cpp +++ b/test/test_range.cpp @@ -89,13 +89,19 @@ TEST_CASE("range: stops short when step > stop-start", "[range]") { REQUIRE( v.size() == 1 ); } -TEST_CASE("Step size of 0 gives an empty range", "[range]") { +TEST_CASE("range: step size of 0 gives an empty range", "[range]") { auto r = range(0, 10, 0); REQUIRE( std::begin(r) == std::end(r) ); auto r2 = range(0, -10, 0); REQUIRE( std::begin(r2) == std::end(r2) ); } +TEST_CASE("range: can create constexpr ranges", "[range]") { + constexpr auto r = range(10); (void)r; + constexpr auto r2 = range(4, 10); (void)r2; + constexpr auto r3 = range(4, 10, 2); (void)r3; +} + TEST_CASE("range: works with a variable start, stop, and step", "[range]") { constexpr int a = 10; constexpr int b = 100; From 33490c1b57acb9f7bdf9c2f18d920a3554703b9a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 29 Jun 2015 21:10:26 -0700 Subject: [PATCH 1206/1866] ranges can be created as constexpr --- range.hpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/range.hpp b/range.hpp index 289ef52c..85cb4965 100644 --- a/range.hpp +++ b/range.hpp @@ -95,11 +95,11 @@ namespace iter { class Range; template - Range range(T); + constexpr Range range(T); template - Range range(T, T); + constexpr Range range(T, T); template - Range range(T, T, T); + constexpr Range range(T, T, T); // General version for everything not a float template @@ -112,13 +112,13 @@ namespace iter { const T stop; const T step; - Range(T in_stop) + constexpr Range(T in_stop) : start{0}, stop{in_stop}, step{1} { } - Range(T in_start, T in_stop, T in_step =1) + constexpr Range(T in_start, T in_stop, T in_step =1) : start{in_start}, stop{in_stop}, step{in_step} @@ -247,19 +247,18 @@ namespace iter { }; template - Range range(T stop) { + constexpr Range range(T stop) { return {stop}; } template - Range range(T start, T stop) { + constexpr Range range(T start, T stop) { return {start, stop}; } template - Range range(T start, T stop, T step) { - if (step == T(0)) return {0}; - return {start, stop, step}; + constexpr Range range(T start, T stop, T step) { + return step == T(0) ? Range{0} : Range{start, stop, step}; } } From ce00107424214e0e57b126563e5f4e76f178470b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 29 Jun 2015 21:19:59 -0700 Subject: [PATCH 1207/1866] adds more constexprs to range This will be extended with C++14 constexpr functions. I could mangle a lot here with ternaries to make them work with constexpr, but without ++ it doesn't really help. --- range.hpp | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/range.hpp b/range.hpp index 85cb4965..1d0928b2 100644 --- a/range.hpp +++ b/range.hpp @@ -20,17 +20,17 @@ namespace iter { T value_{}; T step_{}; public: - RangeIterData() =default; - RangeIterData(T in_value, T in_step) + constexpr RangeIterData() =default; + constexpr RangeIterData(T in_value, T in_step) : value_{in_value}, step_{in_step} { } - T value() const { + constexpr T value() const { return this->value_; } - T step() const { + constexpr T step() const { return this->step_; } @@ -38,11 +38,11 @@ namespace iter { this->value_ += step_; } - bool operator==(const RangeIterData& other) const { + constexpr bool operator==(const RangeIterData& other) const { return this->value_ == other.value_; } - bool operator!=(const RangeIterData& other) const { + constexpr bool operator!=(const RangeIterData& other) const { return !(*this == other); } }; @@ -56,18 +56,18 @@ namespace iter { T step_{}; unsigned long steps_taken{}; public: - RangeIterData() =default; - RangeIterData(T in_start, T in_step) + constexpr RangeIterData() =default; + constexpr RangeIterData(T in_start, T in_step) : start_{in_start}, value_{in_start}, step_{in_step} { } - T value() const { + constexpr T value() const { return this->value_; } - T step() const { + constexpr T step() const { return this->step_; } @@ -77,15 +77,15 @@ namespace iter { (this->step_ * this->steps_taken); } - bool operator==(const RangeIterData& other) const { + constexpr bool operator==(const RangeIterData& other) const { // if the difference between the two values is less than the // step size, they are considered equal - T diff = this->value_ < other.value_ ? - other.value_ - this->value_ : this->value_ - other.value_; - return diff < step_; + return (this->value_ < other.value_ ? + other.value_ - this->value_ : + this->value_ - other.value_) < this->step_; } - bool operator!=(const RangeIterData& other) const { + constexpr bool operator!=(const RangeIterData& other) const { return !(*this == other); } }; @@ -174,18 +174,18 @@ namespace iter { } public: - Iterator() =default; + constexpr Iterator() =default; - Iterator(T in_value, T in_step, bool in_is_end) + constexpr Iterator(T in_value, T in_step, bool in_is_end) : data(in_value, in_step), is_end{in_is_end} { } - T operator*() const { + constexpr T operator*() const { return this->data.value(); } - ArrowProxy operator->() const { + constexpr ArrowProxy operator->() const { return {**this}; } @@ -237,11 +237,11 @@ namespace iter { } }; - Iterator begin() const { + constexpr Iterator begin() const { return {start, step, false}; } - Iterator end() const { + constexpr Iterator end() const { return {stop, step, true}; } }; From 494f56eb660e80fe9d3fb4cba8e6fc21c0cfd0cd Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 29 Jun 2015 21:22:30 -0700 Subject: [PATCH 1208/1866] tests creating a constexpr iterator --- test/test_range.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test_range.cpp b/test/test_range.cpp index f9b29010..d2c21617 100644 --- a/test/test_range.cpp +++ b/test/test_range.cpp @@ -100,6 +100,10 @@ TEST_CASE("range: can create constexpr ranges", "[range]") { constexpr auto r = range(10); (void)r; constexpr auto r2 = range(4, 10); (void)r2; constexpr auto r3 = range(4, 10, 2); (void)r3; + + constexpr auto it = r2.begin(); // std::begin isn't constexpr + constexpr auto i = *it; + static_assert(i == 4, "range's begin has the wrong value"); } TEST_CASE("range: works with a variable start, stop, and step", "[range]") { From f6606acf734ed29dce8acd8dbe0615cbb1786664 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 29 Jun 2015 21:24:21 -0700 Subject: [PATCH 1209/1866] tests range iters constexpr-ness --- test/test_range.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/test_range.cpp b/test/test_range.cpp index d2c21617..887cee8b 100644 --- a/test/test_range.cpp +++ b/test/test_range.cpp @@ -104,6 +104,11 @@ TEST_CASE("range: can create constexpr ranges", "[range]") { constexpr auto it = r2.begin(); // std::begin isn't constexpr constexpr auto i = *it; static_assert(i == 4, "range's begin has the wrong value"); + + constexpr auto rf = range(10.0); + constexpr auto itf = rf.begin(); + constexpr auto f = *itf; + static_assert(f == 0.0, "range's begin has tho wrong value (float)"); } TEST_CASE("range: works with a variable start, stop, and step", "[range]") { From 144ff04e052604c2dc813a75d0b4a152ae598070 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 29 Jun 2015 22:16:40 -0700 Subject: [PATCH 1210/1866] adds constexpr to count() --- count.hpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/count.hpp b/count.hpp index c4e62087..c12263e0 100644 --- a/count.hpp +++ b/count.hpp @@ -8,15 +8,19 @@ namespace iter { template - auto count(T start, T step) -> decltype(range(start, start, start)) { - // 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(); - return range(start, stop, step); + constexpr auto count(T start, T step) + -> decltype(range(start, start, start)) { + // if step is < 0, stop is numeric min, otherwise numeric max + return range( + start, + step < T(0) ? std::numeric_limits::min() : + std::numeric_limits::max(), + step); } template - auto count(T start =T(0)) -> decltype(range(start, start)) { + constexpr auto count(T start =T(0)) + -> decltype(range(start, start)) { return count(start, T(1)); } } From 22b3c7d5c036bdac240a4ef23f1b8893bc3dccaa Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 29 Jun 2015 22:16:44 -0700 Subject: [PATCH 1211/1866] tests count with constexpr --- test/test_count.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/test_count.cpp b/test/test_count.cpp index 12b1347b..0b861bbf 100644 --- a/test/test_count.cpp +++ b/test/test_count.cpp @@ -53,6 +53,16 @@ TEST_CASE("count: with step > 1", "[count]") { REQUIRE( v == vc ); } +TEST_CASE("count: can bo constexpr", "[count]") { + constexpr auto c = count(); + constexpr auto c2 = count(5); (void)c2; + constexpr auto c3 = count(5, 2); (void)c3; + + constexpr auto it = c.begin(); + constexpr auto i = *it; + static_assert(i == 0, "count begin not correct value"); +} + TEST_CASE("count: iterator meets requirements", "[count]") { auto c = count(); REQUIRE( itertest::IsIterator::value ); From 7f500b18bf4f62919d1c2dc3e915a82211f4e79f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 29 Jun 2015 22:30:16 -0700 Subject: [PATCH 1212/1866] noexcept like a boss --- range.hpp | 77 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 41 insertions(+), 36 deletions(-) diff --git a/range.hpp b/range.hpp index 1d0928b2..f412a93b 100644 --- a/range.hpp +++ b/range.hpp @@ -20,29 +20,31 @@ namespace iter { T value_{}; T step_{}; public: - constexpr RangeIterData() =default; - constexpr RangeIterData(T in_value, T in_step) + constexpr RangeIterData() noexcept =default; + constexpr RangeIterData(T in_value, T in_step) noexcept : value_{in_value}, step_{in_step} { } - constexpr T value() const { + constexpr T value() const noexcept { return this->value_; } - constexpr T step() const { + constexpr T step() const noexcept { return this->step_; } - void inc() { + void inc() noexcept { this->value_ += step_; } - constexpr bool operator==(const RangeIterData& other) const { + constexpr bool operator==(const RangeIterData& other) + const noexcept { return this->value_ == other.value_; } - constexpr bool operator!=(const RangeIterData& other) const { + constexpr bool operator!=(const RangeIterData& other) + const noexcept { return !(*this == other); } }; @@ -56,28 +58,29 @@ namespace iter { T step_{}; unsigned long steps_taken{}; public: - constexpr RangeIterData() =default; - constexpr RangeIterData(T in_start, T in_step) + constexpr RangeIterData() noexcept =default; + constexpr RangeIterData(T in_start, T in_step) noexcept : start_{in_start}, value_{in_start}, step_{in_step} { } - constexpr T value() const { + constexpr T value() const noexcept { return this->value_; } - constexpr T step() const { + constexpr T step() const noexcept { return this->step_; } - void inc() { + void inc() noexcept { ++this->steps_taken; value_ = this->start_ + (this->step_ * this->steps_taken); } - constexpr bool operator==(const RangeIterData& other) const { + constexpr bool operator==(const RangeIterData& other) + const noexcept { // if the difference between the two values is less than the // step size, they are considered equal return (this->value_ < other.value_ ? @@ -85,8 +88,9 @@ namespace iter { this->value_ - other.value_) < this->step_; } - constexpr bool operator!=(const RangeIterData& other) const { - return !(*this == other); + constexpr bool operator!=(const RangeIterData& other) + const noexcept { + return !(*this == other); } }; @@ -95,11 +99,11 @@ namespace iter { class Range; template - constexpr Range range(T); + constexpr Range range(T) noexcept; template - constexpr Range range(T, T); + constexpr Range range(T, T) noexcept; template - constexpr Range range(T, T, T); + constexpr Range range(T, T, T) noexcept; // General version for everything not a float template @@ -112,13 +116,13 @@ namespace iter { const T stop; const T step; - constexpr Range(T in_stop) + constexpr Range(T in_stop) noexcept : start{0}, stop{in_stop}, step{1} { } - constexpr Range(T in_start, T in_stop, T in_step =1) + constexpr Range(T in_start, T in_stop, T in_step =1) noexcept : start{in_start}, stop{in_stop}, step{in_step} @@ -144,7 +148,7 @@ namespace iter { // compare unsigned values static bool not_equal_to_impl( const Iterator& iter, const Iterator& end_iter, - std::true_type ) { + std::true_type ) noexcept { assert(!iter.is_end); assert(end_iter.is_end); return iter.data.value() < end_iter.data.value(); @@ -153,7 +157,7 @@ namespace iter { // compare signed values static bool not_equal_to_impl( const Iterator& iter, const Iterator& end_iter, - std::false_type) { + std::false_type) noexcept { assert(!iter.is_end); assert(end_iter.is_end); return !(iter.data.step() > 0 && iter.data.value() @@ -162,8 +166,8 @@ namespace iter { <= end_iter.data.value()); } - static bool not_equal_to_end( - const Iterator& lhs, const Iterator& rhs) { + static bool not_equal_to_end(const Iterator& lhs, + const Iterator& rhs) noexcept{ if (rhs.is_end) { return not_equal_to_impl( lhs, rhs, std::is_unsigned{}); @@ -174,27 +178,28 @@ namespace iter { } public: - constexpr Iterator() =default; + constexpr Iterator() noexcept =default; constexpr Iterator(T in_value, T in_step, bool in_is_end) + noexcept : data(in_value, in_step), is_end{in_is_end} { } - constexpr T operator*() const { + constexpr T operator*() const noexcept { return this->data.value(); } - constexpr ArrowProxy operator->() const { + constexpr ArrowProxy operator->() const noexcept { return {**this}; } - Iterator& operator++() { + Iterator& operator++() noexcept { this->data.inc(); return *this; } - Iterator operator++(int) { + Iterator operator++(int) noexcept { auto ret = *this; ++*this; return ret; @@ -221,7 +226,7 @@ namespace iter { // Two end iterators will compare equal // // Two non-end iterators will compare by their stored values - bool operator!=(const Iterator& other) const { + bool operator!=(const Iterator& other) const noexcept { if (this->is_end && other.is_end) { return false; } @@ -232,32 +237,32 @@ namespace iter { return not_equal_to_end(*this, other); } - bool operator==(const Iterator& other) const { + bool operator==(const Iterator& other) const noexcept { return !(*this != other); } }; - constexpr Iterator begin() const { + constexpr Iterator begin() const noexcept { return {start, step, false}; } - constexpr Iterator end() const { + constexpr Iterator end() const noexcept { return {stop, step, true}; } }; template - constexpr Range range(T stop) { + constexpr Range range(T stop) noexcept { return {stop}; } template - constexpr Range range(T start, T stop) { + constexpr Range range(T start, T stop) noexcept { return {start, stop}; } template - constexpr Range range(T start, T stop, T step) { + constexpr Range range(T start, T stop, T step) noexcept { return step == T(0) ? Range{0} : Range{start, stop, step}; } } From 8a87992272d085f4da547c810848760635d88e26 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 29 Jun 2015 22:52:40 -0700 Subject: [PATCH 1213/1866] noexcept like a boss --- count.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/count.hpp b/count.hpp index c12263e0..eec82f4e 100644 --- a/count.hpp +++ b/count.hpp @@ -8,7 +8,7 @@ namespace iter { template - constexpr auto count(T start, T step) + constexpr auto count(T start, T step) noexcept -> decltype(range(start, start, start)) { // if step is < 0, stop is numeric min, otherwise numeric max return range( @@ -19,7 +19,7 @@ namespace iter { } template - constexpr auto count(T start =T(0)) + constexpr auto count(T start =T(0)) noexcept -> decltype(range(start, start)) { return count(start, T(1)); } From cd8eb30924d31aea824638e8b8295155934c66db Mon Sep 17 00:00:00 2001 From: Jiri Hoogland Date: Fri, 10 Jul 2015 22:46:04 -0400 Subject: [PATCH 1214/1866] Fix OSX build --- examples/groupby_examples.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/groupby_examples.cpp b/examples/groupby_examples.cpp index e4ae4048..c18f9a4c 100644 --- a/examples/groupby_examples.cpp +++ b/examples/groupby_examples.cpp @@ -5,9 +5,14 @@ #include #include +// fix OSX compilation +static int string_length(const std::string & str) +{ + return str.length(); +} int main() { - auto len = std::mem_fn(&std::string::length); + auto len = string_length; std::vector vec = { "hi", "ab", "ho", "abc", "def", From 47b6494f918bc3889dc74c8515b3eda1a329119d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 12 Jul 2015 12:20:03 -0700 Subject: [PATCH 1215/1866] tests that repeat can be constexpr --- test/test_repeat.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/test_repeat.cpp b/test/test_repeat.cpp index 59d0256d..3cb9e45f 100644 --- a/test/test_repeat.cpp +++ b/test/test_repeat.cpp @@ -24,6 +24,24 @@ TEST_CASE("repeat: one argument keeps giving value back", "[repeat]") { REQUIRE( *it == 'a' ); } +TEST_CASE("repeat: can be used as constexpr", "[repeat]") { + static constexpr char c = 'a'; + { + constexpr auto r = repeat(c); + constexpr auto i = r.begin(); + constexpr char c2 = *i; + static_assert(c == c2, "repeat value not as expected"); + constexpr auto i2 = ++i; (void)i2; + } + + { + constexpr auto r = repeat(c, 2); + constexpr auto i = r.begin(); + constexpr char c2 = *i; + static_assert( c2 == c, "repeat value not as expected"); + } +} + TEST_CASE("repeat: two argument repeats a number of times", "[repeat]") { auto r = repeat('a', 3); std::string s(std::begin(r), std::end(r)); From d315cee4498746b169d65e7a60410799f8626469 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 12 Jul 2015 12:21:55 -0700 Subject: [PATCH 1216/1866] adds constexpr spec to repeat --- repeat.hpp | 124 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 86 insertions(+), 38 deletions(-) diff --git a/repeat.hpp b/repeat.hpp index 5f3f8ccf..b2449baf 100644 --- a/repeat.hpp +++ b/repeat.hpp @@ -6,54 +6,40 @@ #include namespace iter { - - // must be negative - constexpr int INFINITE_REPEAT = -1; - - template - class Repeater; - template - Repeater repeat(T&&); + class RepeaterWithCount ; template - Repeater repeat(T&&, int); + constexpr RepeaterWithCount repeat(T&&, int); template - class Repeater { - friend Repeater repeat(T&&); - friend Repeater repeat(T&&, int); + class RepeaterWithCount { + friend RepeaterWithCount repeat(T&&, int); private: - using TPlain = typename std::remove_reference::type; T elem; int count; - Repeater(T e, int c) + constexpr RepeaterWithCount(T e, int c) : elem(std::forward(e)), count{c} { } - public: + using TPlain = typename std::remove_reference::type; + public: class Iterator - : public std::iterator + : public std::iterator { private: - TPlain* elem; + const TPlain *elem; int count; public: - Iterator(TPlain* e, int c) + constexpr Iterator(const TPlain* e, int c) : elem{e}, count{c} { } - // count down to 0 - // INFINITE_REPEAT will be negative, and in that case - // the value is never decremented, it will always compare - // != to an end iterator Iterator& operator++() { - if (this->count > 0) { - --this->count; - } + --this->count; return *this; } @@ -63,43 +49,105 @@ namespace iter { return ret; } - bool operator!=(const Iterator& other) const { + constexpr bool operator!=(const Iterator& other) const { return !(*this == other); } - bool operator==(const Iterator& other) const { + constexpr bool operator==(const Iterator& other) const { return this->count == other.count; } - T& operator*() { + constexpr const TPlain& operator*() const { return *this->elem; } - TPlain* operator->() { + constexpr const TPlain* operator->() const { return this->elem; } }; - Iterator begin() { + constexpr Iterator begin() { return {&this->elem, this->count}; } - Iterator end() { + constexpr Iterator end() { return {&this->elem, 0}; } }; - - template - Repeater repeat(T&& e) { - return {std::forward(e), INFINITE_REPEAT}; - } template - Repeater repeat(T&& e, int count) { - // if count is negative, pass 0 instead + constexpr RepeaterWithCount repeat(T&& e, int count) { return {std::forward(e), count < 0 ? 0 : count}; } + + template + class Repeater; + + template + constexpr Repeater repeat(T&&); + + template + class Repeater{ + friend Repeater repeat(T&&); + private: + using TPlain = typename std::remove_reference::type; + T elem; + + constexpr Repeater(T e) + : elem(std::forward(e)) + { } + public: + class Iterator + : public std::iterator + { + private: + const TPlain *elem; + + public: + constexpr Iterator(const TPlain* e) + : elem{e} + { } + + constexpr const Iterator& operator++() const { + return *this; + } + + constexpr Iterator operator++(int) const { + return *this; + } + + constexpr bool operator!=(const Iterator&) const { + return true; + } + + constexpr bool operator==(const Iterator&) const { + return false; + } + + constexpr const TPlain& operator*() const { + return *this->elem; + } + + constexpr const TPlain* operator->() const { + return this->elem; + } + }; + + + constexpr Iterator begin() { + return {&this->elem}; + } + + constexpr Iterator end() { + return {nullptr}; + } + }; + + template + constexpr Repeater repeat(T&& e) { + return {std::forward(e)}; + } } #endif From 443effb559293a81c94367402d361edc0d59534a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 18 Aug 2015 15:22:28 -0700 Subject: [PATCH 1217/1866] uses first_type instead of decltype(first) --- enumerate.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 535b510f..e5df1ca9 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -47,8 +47,8 @@ namespace iter { class IterYield : public BasePair { public: using BasePair::BasePair; - decltype(BasePair::first)& index = BasePair::first; - decltype(BasePair::second)& element = BasePair::second; + typename BasePair::first_type& index = BasePair::first; + typename BasePair::second_type& element = BasePair::second; }; // Holds an iterator of the contained type and a size_t for the From 1bc2f2a56ccafabce6b7218bb5f18a0f80e853b3 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Wed, 19 Aug 2015 13:26:40 -0700 Subject: [PATCH 1218/1866] removes explicit zip<>::iterator constructors --- zip.hpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/zip.hpp b/zip.hpp index 59171e48..d8cf5457 100644 --- a/zip.hpp +++ b/zip.hpp @@ -114,10 +114,6 @@ namespace iter { public: constexpr static const bool is_base_iter = true; - Iterator() { } - Iterator(const Iterator&) { } - Iterator& operator=(const Iterator&) { return *this; } - Iterator& operator++() { return *this; } From a6c2593e9e2b2359dfee414b28ff7408561419e4 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Wed, 19 Aug 2015 21:54:34 -0700 Subject: [PATCH 1219/1866] adds clang-format config --- .clang-format | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..b5f272f2 --- /dev/null +++ b/.clang-format @@ -0,0 +1,11 @@ +--- +Language: Cpp +BasedOnStyle: Google +AlignAfterOpenBracket: false +AllowShortFunctionsOnASingleLine: Empty +AllowShortLoopsOnASingleLine: false +BreakBeforeBinaryOperators: NonAssignment +DerivePointerAlignment: false +NamespaceIndentation: All +... + From 22a2e784586dcf3a99ea58816b99b452730a92da Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Wed, 19 Aug 2015 21:57:45 -0700 Subject: [PATCH 1220/1866] total reformat Things were messy, I have clang-format, I'm using it. --- accumulate.hpp | 291 +++++++------- chain.hpp | 583 ++++++++++++++-------------- combinations.hpp | 259 ++++++------- combinations_with_replacement.hpp | 229 ++++++----- compress.hpp | 290 +++++++------- count.hpp | 29 +- cycle.hpp | 164 ++++---- dropwhile.hpp | 226 ++++++----- enumerate.hpp | 185 +++++---- filter.hpp | 292 +++++++------- filterfalse.hpp | 165 ++++---- groupby.hpp | 609 ++++++++++++++---------------- grouper.hpp | 211 +++++------ imap.hpp | 246 ++++++------ iteratoriterator.hpp | 513 ++++++++++++------------- iterbase.hpp | 474 +++++++++++------------ itertools.hpp | 2 - permutations.hpp | 176 ++++----- powerset.hpp | 162 ++++---- product.hpp | 293 +++++++------- range.hpp | 470 +++++++++++------------ repeat.hpp | 262 +++++++------ reversed.hpp | 259 ++++++------- slice.hpp | 267 +++++++------ sliding_window.hpp | 194 +++++----- sorted.hpp | 118 +++--- takewhile.hpp | 232 ++++++------ unique_everseen.hpp | 75 ++-- unique_justseen.hpp | 53 ++- zip.hpp | 271 +++++++------ zip_longest.hpp | 281 +++++++------- 31 files changed, 3732 insertions(+), 4149 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index bc006abf..672212f6 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -12,166 +12,147 @@ namespace iter { - //Forward declarations of Accumulator and accumulate - template - class Accumulator; - - template - Accumulator accumulate( - Container&&, AccumulateFunc); - - template - Accumulator, AccumulateFunc> accumulate( - std::initializer_list, AccumulateFunc); - - template - class Accumulator { - private: - Container container; - AccumulateFunc accumulate_func; - - friend Accumulator accumulate( - Container&&, AccumulateFunc); - - template - friend Accumulator, AF> accumulate( - std::initializer_list, AF); - - // AccumVal must be default constructible - using AccumVal = - typename std::remove_reference< - typename std::result_of, - iterator_deref)>::type>::type; - - Accumulator(Container&& in_container, - AccumulateFunc in_accumulate_func) - : container(std::forward(in_container)), - accumulate_func(in_accumulate_func) - { } - public: - - class Iterator - : public std::iterator - { - private: - iterator_type sub_iter; - iterator_type sub_end; - AccumulateFunc *accumulate_func; - std::unique_ptr acc_val; - public: - Iterator(iterator_type&& iter, - iterator_type&& end, - AccumulateFunc in_accumulate_func) - : sub_iter{std::move(iter)}, - sub_end{std::move(end)}, - accumulate_func(&in_accumulate_func), - // only get first value if not an end iterator - acc_val{!(iter != end) ? nullptr : new AccumVal(*iter)} - { } - - Iterator(const Iterator& other) - : sub_iter{other.sub_iter}, - sub_end{other.sub_end}, - accumulate_func{other.accumulate_func}, - acc_val{other.acc_val ? - new AccumVal(*other.acc_val) : nullptr} - { } - - Iterator& operator=(const Iterator& other) { - if (this == &other) return *this; - this->sub_iter = other.sub_iter; - this->sub_end = other.sub_end; - this->accumulate_func = other.accumulate_func; - this->acc_val.reset(other.acc_val ? - new AccumVal(*other.acc_val) : nullptr); - return *this; - } - - Iterator(Iterator&&) =default; - Iterator& operator=(Iterator&&) =default; - - const AccumVal& operator*() const { - return *this->acc_val; - } - - const AccumVal* operator->() const { - return this->acc_val.get(); - } - - Iterator& operator++() { - ++this->sub_iter; - if (this->sub_iter != this->sub_end) { - *this->acc_val = (*accumulate_func)( - *this->acc_val, *this->sub_iter); - } - 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 {std::begin(this->container), - std::end(this->container), - this->accumulate_func}; - } - - Iterator end() { - return {std::end(this->container), - std::end(this->container), - this->accumulate_func}; - } - + // Forward declarations of Accumulator and accumulate + template + class Accumulator; + + template + Accumulator accumulate( + Container&&, AccumulateFunc); + + template + Accumulator, AccumulateFunc> accumulate( + std::initializer_list, AccumulateFunc); + + template + class Accumulator { + private: + Container container; + AccumulateFunc accumulate_func; + + friend Accumulator accumulate( + Container&&, AccumulateFunc); + + template + friend Accumulator, AF> accumulate( + std::initializer_list, AF); + + // AccumVal must be default constructible + using AccumVal = + typename std::remove_reference, iterator_deref)>::type>::type; + + Accumulator(Container&& in_container, AccumulateFunc in_accumulate_func) + : container(std::forward(in_container)), + accumulate_func(in_accumulate_func) {} + + public: + class Iterator : public std::iterator { + private: + iterator_type sub_iter; + iterator_type sub_end; + AccumulateFunc* accumulate_func; + std::unique_ptr acc_val; + + public: + Iterator(iterator_type&& iter, iterator_type&& end, + AccumulateFunc in_accumulate_func) + : sub_iter{std::move(iter)}, + sub_end{std::move(end)}, + accumulate_func(&in_accumulate_func), + // only get first value if not an end iterator + acc_val{!(iter != end) ? nullptr : new AccumVal(*iter)} {} + + Iterator(const Iterator& other) + : sub_iter{other.sub_iter}, + sub_end{other.sub_end}, + accumulate_func{other.accumulate_func}, + acc_val{other.acc_val ? new AccumVal(*other.acc_val) : nullptr} {} + + Iterator& operator=(const Iterator& other) { + if (this == &other) return *this; + this->sub_iter = other.sub_iter; + this->sub_end = other.sub_end; + this->accumulate_func = other.accumulate_func; + this->acc_val.reset( + other.acc_val ? new AccumVal(*other.acc_val) : nullptr); + return *this; + } + + Iterator(Iterator&&) = default; + Iterator& operator=(Iterator&&) = default; + + const AccumVal& operator*() const { + return *this->acc_val; + } + + const AccumVal* operator->() const { + return this->acc_val.get(); + } + + Iterator& operator++() { + ++this->sub_iter; + if (this->sub_iter != this->sub_end) { + *this->acc_val = (*accumulate_func)(*this->acc_val, *this->sub_iter); + } + 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); + } }; - // Helper function to instantiate an Accumulator - template - Accumulator accumulate( - Container&& container, - AccumulateFunc accumulate_func) - { - return {std::forward(container), accumulate_func}; - } - - template - auto accumulate(Container&& container) -> - decltype(accumulate(std::forward(container), - std::plus>::type>{})) - { - return accumulate(std::forward(container), - std::plus>::type>{}); + Iterator begin() { + return {std::begin(this->container), std::end(this->container), + this->accumulate_func}; } - template - Accumulator, AccumulateFunc> accumulate( - std::initializer_list il, - AccumulateFunc accumulate_func) - { - return {std::move(il), accumulate_func}; + Iterator end() { + return {std::end(this->container), std::end(this->container), + this->accumulate_func}; } - - template - auto accumulate(std::initializer_list il) -> - decltype(accumulate(std::move(il), std::plus{})) - { - return accumulate(std::move(il), std::plus{}); - } - + }; + + // Helper function to instantiate an Accumulator + template + Accumulator accumulate( + Container&& container, AccumulateFunc accumulate_func) { + return {std::forward(container), accumulate_func}; + } + + template + auto accumulate(Container&& container) -> decltype(accumulate( + std::forward(container), + std::plus< + typename std::remove_reference>::type>{})) { + return accumulate( + std::forward(container), + std::plus< + typename std::remove_reference>::type>{}); + } + + template + Accumulator, AccumulateFunc> accumulate( + std::initializer_list il, AccumulateFunc accumulate_func) { + return {std::move(il), accumulate_func}; + } + + template + auto accumulate(std::initializer_list il) + -> decltype(accumulate(std::move(il), std::plus{})) { + return accumulate(std::move(il), std::plus{}); + } } #endif diff --git a/chain.hpp b/chain.hpp index 1db17ad0..c2a7db9a 100644 --- a/chain.hpp +++ b/chain.hpp @@ -10,324 +10,293 @@ #include namespace iter { - // rather than a chain function, use a callable object to support - // from_iterable - class ChainMaker; - - template - class Chained { - static_assert( - are_same, - iterator_deref...>::value, - "All chained iterables must have iterators that " - "dereference to the same type, including cv-qualifiers " - "and references."); - - friend class ChainMaker; - template - friend class Chained; - - private: - Container container; - Chained rest_chained; - Chained(Container&& in_container, RestContainers&&... rest) - : container(std::forward(in_container)), - rest_chained{std::forward(rest)...} - { } - - public: - class Iterator - : public std::iterator< - std::input_iterator_tag, - iterator_traits_deref> - { - private: - using RestIter = - typename Chained::Iterator; - iterator_type sub_iter; - iterator_type sub_end; - RestIter rest_iter; - bool at_end; - - public: - Iterator(iterator_type&& s_begin, - iterator_type&& s_end, - RestIter&& in_rest_iter) - : sub_iter{std::move(s_begin)}, - sub_end{std::move(s_end)}, - rest_iter{std::move(in_rest_iter)}, - at_end{!(sub_iter != sub_end)} - { } - - 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; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter || - this->rest_iter != other.rest_iter; - } - - bool operator==(const Iterator& other) const { - return !(*this != other); - } - - iterator_deref operator*() { - return this->at_end ? - *this->rest_iter : *this->sub_iter; - } - - iterator_arrow operator->() { - return this->at_end ? - apply_arrow(this->rest_iter) + // rather than a chain function, use a callable object to support + // from_iterable + class ChainMaker; + + template + class Chained { + static_assert(are_same, + iterator_deref...>::value, + "All chained iterables must have iterators that " + "dereference to the same type, including cv-qualifiers " + "and references."); + + friend class ChainMaker; + template + friend class Chained; + + private: + Container container; + Chained rest_chained; + Chained(Container&& in_container, RestContainers&&... rest) + : container(std::forward(in_container)), + rest_chained{std::forward(rest)...} {} + + public: + class Iterator : public std::iterator> { + private: + using RestIter = typename Chained::Iterator; + iterator_type sub_iter; + iterator_type sub_end; + RestIter rest_iter; + bool at_end; + + public: + Iterator(iterator_type&& s_begin, + iterator_type&& s_end, RestIter&& in_rest_iter) + : sub_iter{std::move(s_begin)}, + sub_end{std::move(s_end)}, + rest_iter{std::move(in_rest_iter)}, + at_end{!(sub_iter != sub_end)} {} + + 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; + } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + bool operator!=(const Iterator& other) const { + return this->sub_iter != other.sub_iter + || this->rest_iter != other.rest_iter; + } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } + + iterator_deref operator*() { + return this->at_end ? *this->rest_iter : *this->sub_iter; + } + + iterator_arrow operator->() { + return this->at_end ? apply_arrow(this->rest_iter) : apply_arrow(this->sub_iter); - } - - }; + } + }; - Iterator begin() { - return {std::begin(this->container), - std::end(this->container), - std::begin(this->rest_chained)}; - } + Iterator begin() { + return {std::begin(this->container), std::end(this->container), + std::begin(this->rest_chained)}; + } - 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&& in_container) - : container(std::forward(in_container)) - { } - - public: - class Iterator - : public std::iterator< - std::input_iterator_tag, - iterator_traits_deref> - { - private: - iterator_type sub_iter; - iterator_type sub_end; - - public: - Iterator(const iterator_type& s_begin, - const iterator_type& s_end) - : sub_iter{s_begin}, - sub_end{s_end} - { } - - 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_deref operator*() { - return *this->sub_iter; - } - - iterator_arrow operator->() { - return apply_arrow(this->sub_iter); - } - }; - - Iterator begin() { - return {std::begin(this->container), - std::end(this->container)}; - } - - Iterator end() { - return {std::end(this->container), - std::end(this->container)}; - } + 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&& in_container) + : container(std::forward(in_container)) {} + + public: + class Iterator : public std::iterator> { + private: + iterator_type sub_iter; + iterator_type sub_end; + + public: + Iterator(const iterator_type& s_begin, + const iterator_type& s_end) + : sub_iter{s_begin}, sub_end{s_end} {} + + 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_deref operator*() { + return *this->sub_iter; + } + + iterator_arrow operator->() { + return apply_arrow(this->sub_iter); + } }; - template - class ChainedFromIterable { - private: - Container container; - friend class ChainMaker; - ChainedFromIterable(Container&& in_container) - : container(std::forward(in_container)) - { } - - public: - class Iterator - :public std::iterator>> - { - private: - using SubContainer = iterator_deref; - using SubIter = iterator_type; - - iterator_type top_level_iter; - iterator_type top_level_end; - std::unique_ptr sub_iter_p; - std::unique_ptr sub_end_p; - - static std::unique_ptr clone_sub_pointer( - const SubIter* sub_iter) { - return std::unique_ptr{ sub_iter ? - new SubIter{*sub_iter} : nullptr}; - } - - bool sub_iters_differ(const Iterator& other) const { - if (this->sub_iter_p == other.sub_iter_p) { - return false; - } - if (this->sub_iter_p == nullptr - || other.sub_iter_p == nullptr) { - // since the first check tests if they're the same, - // this will return if only one is nullptr - return true; - } - return *this->sub_iter_p != *other.sub_iter_p; - } - - public: - Iterator(iterator_type&& top_iter, - iterator_type&& top_end) - : top_level_iter{std::move(top_iter)}, - top_level_end{std::move(top_end)}, - sub_iter_p{!(top_iter != top_end) ? // iter == end ? - nullptr : new SubIter{std::begin(*top_iter)}}, - sub_end_p{!(top_iter != top_end) ? // iter == end ? - nullptr : new SubIter{std::end(*top_iter)}} - { } - - Iterator(const Iterator& other) - : top_level_iter{other.top_level_iter}, - top_level_end{other.top_level_end}, - sub_iter_p{clone_sub_pointer(other.sub_iter_p.get())}, - sub_end_p{clone_sub_pointer(other.sub_end_p.get())} - { } - - Iterator& operator=(const Iterator& other) { - if (this == &other) return *this; - - this->top_level_iter = other.top_level_iter; - this->top_level_end = other.top_level_end; - this->sub_iter_p = - clone_sub_pointer(other.sub_iter_p.get()); - this->sub_end_p = - clone_sub_pointer(other.sub_end_p.get()); - - return *this; - } - - Iterator(Iterator&&) = default; - Iterator& operator=(Iterator&&) = default; - ~Iterator() = default; - - Iterator& operator++() { - ++*this->sub_iter_p; - if (!(*this->sub_iter_p != *this->sub_end_p)) { - ++this->top_level_iter; - if (this->top_level_iter != this->top_level_end) { - sub_iter_p.reset( - new SubIter{std::begin(*this->top_level_iter)}); - sub_end_p.reset( - new SubIter{std::end(*this->top_level_iter)}); - } else { - sub_iter_p.reset(nullptr); - sub_end_p.reset(nullptr); - } - } - return *this; - } - - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - bool operator!=(const Iterator& other) const { - return this->top_level_iter != other.top_level_iter - || this->sub_iters_differ(other); - } - - bool operator==(const Iterator& other) const { - return !(*this != other); - } - - iterator_deref> operator*() { - return **this->sub_iter_p; - } - - iterator_arrow> operator->() { - return apply_arrow(*this->sub_iter_p); - } - }; - - Iterator begin() { - return {std::begin(this->container), std::end(this->container)}; - } - - Iterator end() { - return {std::end(this->container), std::end(this->container)}; - } + Iterator begin() { + return {std::begin(this->container), std::end(this->container)}; + } + + Iterator end() { + return {std::end(this->container), std::end(this->container)}; + } + }; + + template + class ChainedFromIterable { + private: + Container container; + friend class ChainMaker; + ChainedFromIterable(Container&& in_container) + : container(std::forward(in_container)) {} + + public: + class Iterator : public std::iterator>> { + private: + using SubContainer = iterator_deref; + using SubIter = iterator_type; + + iterator_type top_level_iter; + iterator_type top_level_end; + std::unique_ptr sub_iter_p; + std::unique_ptr sub_end_p; + + static std::unique_ptr clone_sub_pointer( + const SubIter* sub_iter) { + return std::unique_ptr{ + sub_iter ? new SubIter{*sub_iter} : nullptr}; + } + + bool sub_iters_differ(const Iterator& other) const { + if (this->sub_iter_p == other.sub_iter_p) { + return false; + } + if (this->sub_iter_p == nullptr || other.sub_iter_p == nullptr) { + // since the first check tests if they're the same, + // this will return if only one is nullptr + return true; + } + return *this->sub_iter_p != *other.sub_iter_p; + } + + public: + Iterator(iterator_type&& top_iter, + iterator_type&& top_end) + : top_level_iter{std::move(top_iter)}, + top_level_end{std::move(top_end)}, + sub_iter_p{!(top_iter != top_end) + ? // iter == end ? + nullptr + : new SubIter{std::begin(*top_iter)}}, + sub_end_p{!(top_iter != top_end) + ? // iter == end ? + nullptr + : new SubIter{std::end(*top_iter)}} {} + + Iterator(const Iterator& other) + : top_level_iter{other.top_level_iter}, + top_level_end{other.top_level_end}, + sub_iter_p{clone_sub_pointer(other.sub_iter_p.get())}, + sub_end_p{clone_sub_pointer(other.sub_end_p.get())} {} + + Iterator& operator=(const Iterator& other) { + if (this == &other) return *this; + + this->top_level_iter = other.top_level_iter; + this->top_level_end = other.top_level_end; + this->sub_iter_p = clone_sub_pointer(other.sub_iter_p.get()); + this->sub_end_p = clone_sub_pointer(other.sub_end_p.get()); + + return *this; + } + + Iterator(Iterator&&) = default; + Iterator& operator=(Iterator&&) = default; + ~Iterator() = default; + + Iterator& operator++() { + ++*this->sub_iter_p; + if (!(*this->sub_iter_p != *this->sub_end_p)) { + ++this->top_level_iter; + if (this->top_level_iter != this->top_level_end) { + sub_iter_p.reset(new SubIter{std::begin(*this->top_level_iter)}); + sub_end_p.reset(new SubIter{std::end(*this->top_level_iter)}); + } else { + sub_iter_p.reset(nullptr); + sub_end_p.reset(nullptr); + } + } + return *this; + } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + bool operator!=(const Iterator& other) const { + return this->top_level_iter != other.top_level_iter + || this->sub_iters_differ(other); + } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } + + iterator_deref> operator*() { + return **this->sub_iter_p; + } + + iterator_arrow> operator->() { + return apply_arrow(*this->sub_iter_p); + } }; + Iterator begin() { + return {std::begin(this->container), std::end(this->container)}; + } - class ChainMaker { - public: - // expose regular call operator to provide usual chain() - template - Chained operator()(Containers&&... cs) const { - return {std::forward(cs)...}; - } - - // chain.from_iterable - template - ChainedFromIterable from_iterable( - Container&& container) const { - return {std::forward(container)}; - } - }; + Iterator end() { + return {std::end(this->container), std::end(this->container)}; + } + }; + + class ChainMaker { + public: + // expose regular call operator to provide usual chain() + template + Chained operator()(Containers&&... cs) const { + return {std::forward(cs)...}; + } - namespace { - constexpr auto chain = ChainMaker{}; + // chain.from_iterable + template + ChainedFromIterable from_iterable(Container&& container) const { + return {std::forward(container)}; } + }; + namespace { + constexpr auto chain = ChainMaker{}; + } } #endif diff --git a/combinations.hpp b/combinations.hpp index 2f52a7e5..74b93829 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -10,150 +10,139 @@ #include namespace iter { - template - class Combinator; + template + class Combinator; - template - Combinator combinations(Container&&, std::size_t); + template + Combinator combinations(Container&&, std::size_t); + template + Combinator> combinations( + std::initializer_list, std::size_t); + + template + class Combinator { + private: + Container container; + std::size_t length; + + friend Combinator combinations(Container&&, std::size_t); template - Combinator> combinations( - std::initializer_list, std::size_t); - - template - class Combinator { - private: - Container container; - std::size_t length; - - friend Combinator combinations(Container&&,std::size_t); - template - friend Combinator> combinations( - std::initializer_list, std::size_t); - - Combinator(Container&& in_container, std::size_t in_length) - : container(std::forward(in_container)), - length{in_length} - { } - - using IndexVector = std::vector>; - using CombIteratorDeref = IterIterWrapper; - - public: - - class Iterator : - public std::iterator - { - private: - constexpr static const int COMPLETE = -1; - typename std::remove_reference::type *container_p; - CombIteratorDeref indices; - int steps{}; - - public: - Iterator(Container& in_container, std::size_t n) - : container_p{&in_container}, - indices{n} - { - if (n == 0) { - this->steps = COMPLETE; - return; - } - size_t inc = 0; - for (auto& iter : this->indices.get()) { - auto it = std::begin(*this->container_p); - dumb_advance(it, std::end(*this->container_p), inc); - if (it != std::end(*this->container_p)) { - iter = it; - ++inc; - } else { - this->steps = COMPLETE; - break; - } - } - } - - CombIteratorDeref& operator*() { - return this->indices; - } - - CombIteratorDeref *operator->() { - return &this->indices; - } - - - Iterator& operator++() { - for (auto iter = indices.get().rbegin(); - iter != indices.get().rend(); - ++iter) { - ++(*iter); - - //what we have to check here is if the distance between - //the index and the end of indices is >= the distance - //between the item and end of item - auto dist = std::distance( - this->indices.get().rbegin(),iter); - - if (!(dumb_next(*iter, dist) != - std::end(*this->container_p))) { - if ( (iter + 1) != indices.get().rend()) { - size_t inc = 1; - for (auto down = iter; - down != indices.get().rbegin()-1; - --down) { - (*down) = dumb_next(*(iter + 1), 1 + inc); - ++inc; - } - } else { - this->steps = COMPLETE; - break; - } - } else { - break; - } - //we break because none of the rest of the items need - //to be incremented - } - if (this->steps != COMPLETE) { - ++this->steps; - } - return *this; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - bool operator!=(const Iterator& other) const { - return !(*this == other); - } - - bool operator==(const Iterator& other) const { - return this->steps == other.steps; - } - }; - - Iterator begin() { - return {this->container, this->length}; + friend Combinator> combinations( + std::initializer_list, std::size_t); + + Combinator(Container&& in_container, std::size_t in_length) + : container(std::forward(in_container)), length{in_length} {} + + using IndexVector = std::vector>; + using CombIteratorDeref = IterIterWrapper; + + public: + class Iterator + : public std::iterator { + private: + constexpr static const int COMPLETE = -1; + typename std::remove_reference::type* container_p; + CombIteratorDeref indices; + int steps{}; + + public: + Iterator(Container& in_container, std::size_t n) + : container_p{&in_container}, indices{n} { + if (n == 0) { + this->steps = COMPLETE; + return; + } + size_t inc = 0; + for (auto& iter : this->indices.get()) { + auto it = std::begin(*this->container_p); + dumb_advance(it, std::end(*this->container_p), inc); + if (it != std::end(*this->container_p)) { + iter = it; + ++inc; + } else { + this->steps = COMPLETE; + break; + } } - - Iterator end() { - return {this->container, 0}; + } + + CombIteratorDeref& operator*() { + return this->indices; + } + + CombIteratorDeref* operator->() { + return &this->indices; + } + + Iterator& operator++() { + for (auto iter = indices.get().rbegin(); iter != indices.get().rend(); + ++iter) { + ++(*iter); + + // what we have to check here is if the distance between + // the index and the end of indices is >= the distance + // between the item and end of item + auto dist = std::distance(this->indices.get().rbegin(), iter); + + if (!(dumb_next(*iter, dist) != std::end(*this->container_p))) { + if ((iter + 1) != indices.get().rend()) { + size_t inc = 1; + for (auto down = iter; down != indices.get().rbegin() - 1; + --down) { + (*down) = dumb_next(*(iter + 1), 1 + inc); + ++inc; + } + } else { + this->steps = COMPLETE; + break; + } + } else { + break; + } + // we break because none of the rest of the items need + // to be incremented } + if (this->steps != COMPLETE) { + ++this->steps; + } + return *this; + } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + bool operator!=(const Iterator& other) const { + return !(*this == other); + } + + bool operator==(const Iterator& other) const { + return this->steps == other.steps; + } }; - template - Combinator combinations( - Container&& container, std::size_t length) { - return {std::forward(container), length}; + Iterator begin() { + return {this->container, this->length}; } - template - Combinator> combinations( - std::initializer_list il, std::size_t length) { - return {std::move(il), length}; + Iterator end() { + return {this->container, 0}; } + }; + + template + Combinator combinations( + Container&& container, std::size_t length) { + return {std::forward(container), length}; + } + + template + Combinator> combinations( + std::initializer_list il, std::size_t length) { + return {std::move(il), length}; + } } #endif diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index 0a1d11c6..d579d8ef 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -11,135 +11,122 @@ namespace iter { - template - class CombinatorWithReplacement; + template + class CombinatorWithReplacement; - template - CombinatorWithReplacement combinations_with_replacement( - Container&&, std::size_t); + template + CombinatorWithReplacement combinations_with_replacement( + Container&&, std::size_t); + template + CombinatorWithReplacement> + combinations_with_replacement(std::initializer_list, std::size_t); + + template + class CombinatorWithReplacement { + private: + Container container; + std::size_t length; + + friend CombinatorWithReplacement combinations_with_replacement( + Container&&, std::size_t); template - CombinatorWithReplacement> - combinations_with_replacement( - std::initializer_list, std::size_t); - - template - class CombinatorWithReplacement { - private: - Container container; - std::size_t length; - - friend CombinatorWithReplacement - combinations_with_replacement( - Container&& ,std::size_t); - template - friend CombinatorWithReplacement> - combinations_with_replacement( - std::initializer_list, std::size_t); - - CombinatorWithReplacement(Container&& in_container, std::size_t n) - : container(std::forward(in_container)), - length{n} - { } - - using IndexVector = std::vector>; - using CombIteratorDeref = IterIterWrapper; - - public: - class Iterator : - public std::iterator - { - private: - constexpr static const int COMPLETE = -1; - typename std::remove_reference::type *container_p; - CombIteratorDeref indices; - int steps; - - public: - Iterator(Container& in_container, std::size_t n) - : container_p{&in_container}, - indices(n, std::begin(in_container)), - steps{(std::begin(in_container) - != std::end(in_container) - && n) - ? 0 : COMPLETE} - { } - - CombIteratorDeref& operator*() { - return this->indices; - } - - CombIteratorDeref *operator->() { - return &this->indices; - } - - Iterator& operator++() { - for (auto iter = indices.get().rbegin(); - iter != indices.get().rend(); - ++iter) { - ++(*iter); - if (!(*iter != std::end(*this->container_p))) { - if ( (iter + 1) != indices.get().rend()) { - for (auto down = iter; - down != indices.get().rbegin()-1; - --down) { - (*down) = dumb_next(*(iter + 1)); - } - } else { - this->steps = COMPLETE; - break; - } - } else { - //we break because none of the rest of the items - //need to be incremented - break; - } - } - if (this->steps != COMPLETE) { - ++this->steps; - } - return *this; - } - - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - bool operator!=(const Iterator& other) const { - return !(*this == other); - } - - bool operator==(const Iterator& other) const { - return this->steps == other.steps; - } - - }; - - Iterator begin() { - return {this->container, this->length}; - } - - Iterator end() { - return {this->container, 0}; - } + friend CombinatorWithReplacement> + combinations_with_replacement(std::initializer_list, std::size_t); + + CombinatorWithReplacement(Container&& in_container, std::size_t n) + : container(std::forward(in_container)), length{n} {} + + using IndexVector = std::vector>; + using CombIteratorDeref = IterIterWrapper; + + public: + class Iterator + : public std::iterator { + private: + constexpr static const int COMPLETE = -1; + typename std::remove_reference::type* container_p; + CombIteratorDeref indices; + int steps; + + public: + Iterator(Container& in_container, std::size_t n) + : container_p{&in_container}, + indices(n, std::begin(in_container)), + steps{(std::begin(in_container) != std::end(in_container) && n) + ? 0 + : COMPLETE} {} + + CombIteratorDeref& operator*() { + return this->indices; + } + + CombIteratorDeref* operator->() { + return &this->indices; + } + + Iterator& operator++() { + for (auto iter = indices.get().rbegin(); iter != indices.get().rend(); + ++iter) { + ++(*iter); + if (!(*iter != std::end(*this->container_p))) { + if ((iter + 1) != indices.get().rend()) { + for (auto down = iter; down != indices.get().rbegin() - 1; + --down) { + (*down) = dumb_next(*(iter + 1)); + } + } else { + this->steps = COMPLETE; + break; + } + } else { + // we break because none of the rest of the items + // need to be incremented + break; + } + } + if (this->steps != COMPLETE) { + ++this->steps; + } + return *this; + } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + bool operator!=(const Iterator& other) const { + return !(*this == other); + } + + bool operator==(const Iterator& other) const { + return this->steps == other.steps; + } }; - template - CombinatorWithReplacement combinations_with_replacement( - Container&& container, std::size_t length) { - return {std::forward(container), length}; + Iterator begin() { + return {this->container, this->length}; } - template - CombinatorWithReplacement> - combinations_with_replacement( - std::initializer_list il, std::size_t length) { - return {std::move(il), length}; + Iterator end() { + return {this->container, 0}; } + }; + + template + CombinatorWithReplacement combinations_with_replacement( + Container&& container, std::size_t length) { + return {std::forward(container), length}; + } + + template + CombinatorWithReplacement> + combinations_with_replacement( + std::initializer_list il, std::size_t length) { + return {std::move(il), length}; + } } #endif diff --git a/compress.hpp b/compress.hpp index cc79b930..5089228d 100644 --- a/compress.hpp +++ b/compress.hpp @@ -9,169 +9,155 @@ namespace iter { - //Forward declarations of Compressed and compress - template - class Compressed; + // Forward declarations of Compressed and compress + template + class Compressed; - template - Compressed compress(Container&&, Selector&&); + template + Compressed compress(Container&&, Selector&&); - template - Compressed, Selector> compress( - std::initializer_list, Selector&&); + template + Compressed, Selector> compress( + std::initializer_list, Selector&&); - template - Compressed> compress( - Container&&, std::initializer_list); + template + Compressed> compress( + Container&&, std::initializer_list); - template - Compressed, std::initializer_list> compress( - std::initializer_list, std::initializer_list); - - template - class Compressed { - private: - Container container; - Selector selectors; - - // The only thing allowed to directly instantiate an Compressed is - // the compress function - friend Compressed compress( - Container&&, Selector&&); - - template - friend Compressed, Sel> compress( - std::initializer_list, Sel&&); - - template - friend Compressed> compress( - Con&&, std::initializer_list); - - template - friend Compressed, - std::initializer_list> compress( - std::initializer_list, std::initializer_list); - - - // Selector::Iterator type - using selector_iter_type = decltype(std::begin(selectors)); - - // Value constructor for use only in the compress function - Compressed(Container&& in_container, Selector&& in_selectors) - : container(std::forward(in_container)), - selectors(std::forward(in_selectors)) - { } - - public: - - class Iterator - : public std::iterator> - { - private: - iterator_type sub_iter; - iterator_type sub_end; - - selector_iter_type selector_iter; - selector_iter_type selector_end; - - void increment_iterators() { - ++this->sub_iter; - ++this->selector_iter; - } - - void skip_failures() { - while (this->sub_iter != this->sub_end - && this->selector_iter != this->selector_end - && !*this->selector_iter) { - this->increment_iterators(); - } - } - - public: - Iterator(iterator_type&& cont_iter, - iterator_type&& cont_end, - selector_iter_type&& sel_iter, - selector_iter_type&& sel_end) - : sub_iter{std::move(cont_iter)}, - sub_end{std::move(cont_end)}, - selector_iter{std::move(sel_iter)}, - selector_end{std::move(sel_end)} - { - this->skip_failures(); - } - - iterator_deref operator*() { - return *this->sub_iter; - } - - iterator_arrow operator->() { - return apply_arrow(this->sub_iter); - } - - Iterator& operator++() { - this->increment_iterators(); - this->skip_failures(); - return *this; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter - && this->selector_iter != other.selector_iter; - } - - bool operator==(const Iterator& other) const { - return !(*this != other); - } - }; - - Iterator begin() { - return {std::begin(this->container), std::end(this->container), - std::begin(this->selectors), std::end(this->selectors)}; - } - - Iterator end() { - return {std::end(this->container), std::end(this->container), - std::end(this->selectors), std::end(this->selectors)}; - } + template + Compressed, std::initializer_list> compress( + std::initializer_list, std::initializer_list); - }; + template + class Compressed { + private: + Container container; + Selector selectors; - // Helper function to instantiate an Compressed - template - Compressed compress( - Container&& container, Selector&& selectors) { - return {std::forward(container), - std::forward(selectors)}; - } + // The only thing allowed to directly instantiate an Compressed is + // the compress function + friend Compressed compress(Container&&, Selector&&); - template - Compressed, Selector> compress( - std::initializer_list data, Selector&& selectors) { - return {std::move(data), - std::forward(selectors)}; - } + template + friend Compressed, Sel> compress( + std::initializer_list, Sel&&); - template - Compressed> compress( - Container&& container, std::initializer_list selectors) { - return {std::forward(container), - std::move(selectors)}; - } + template + friend Compressed> compress( + Con&&, std::initializer_list); template - Compressed, std::initializer_list> compress( - std::initializer_list data, - std::initializer_list selectors) { - return {std::move(data), - std::move(selectors)}; + friend Compressed, std::initializer_list> + compress(std::initializer_list, std::initializer_list); + + // Selector::Iterator type + using selector_iter_type = decltype(std::begin(selectors)); + + // Value constructor for use only in the compress function + Compressed(Container&& in_container, Selector&& in_selectors) + : container(std::forward(in_container)), + selectors(std::forward(in_selectors)) {} + + public: + class Iterator : public std::iterator> { + private: + iterator_type sub_iter; + iterator_type sub_end; + + selector_iter_type selector_iter; + selector_iter_type selector_end; + + void increment_iterators() { + ++this->sub_iter; + ++this->selector_iter; + } + + void skip_failures() { + while (this->sub_iter != this->sub_end + && this->selector_iter != this->selector_end + && !*this->selector_iter) { + this->increment_iterators(); + } + } + + public: + Iterator(iterator_type&& cont_iter, + iterator_type&& cont_end, selector_iter_type&& sel_iter, + selector_iter_type&& sel_end) + : sub_iter{std::move(cont_iter)}, + sub_end{std::move(cont_end)}, + selector_iter{std::move(sel_iter)}, + selector_end{std::move(sel_end)} { + this->skip_failures(); + } + + iterator_deref operator*() { + return *this->sub_iter; + } + + iterator_arrow operator->() { + return apply_arrow(this->sub_iter); + } + + Iterator& operator++() { + this->increment_iterators(); + this->skip_failures(); + return *this; + } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + bool operator!=(const Iterator& other) const { + return this->sub_iter != other.sub_iter + && this->selector_iter != other.selector_iter; + } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } + }; + + Iterator begin() { + return {std::begin(this->container), std::end(this->container), + std::begin(this->selectors), std::end(this->selectors)}; + } + + Iterator end() { + return {std::end(this->container), std::end(this->container), + std::end(this->selectors), std::end(this->selectors)}; } + }; + + // Helper function to instantiate an Compressed + template + Compressed compress( + Container&& container, Selector&& selectors) { + return { + std::forward(container), std::forward(selectors)}; + } + + template + Compressed, Selector> compress( + std::initializer_list data, Selector&& selectors) { + return {std::move(data), std::forward(selectors)}; + } + + template + Compressed> compress( + Container&& container, std::initializer_list selectors) { + return {std::forward(container), std::move(selectors)}; + } + + template + Compressed, std::initializer_list> compress( + std::initializer_list data, std::initializer_list selectors) { + return {std::move(data), std::move(selectors)}; + } } #endif diff --git a/count.hpp b/count.hpp index eec82f4e..0a67d971 100644 --- a/count.hpp +++ b/count.hpp @@ -7,23 +7,20 @@ namespace iter { - template - constexpr auto count(T start, T step) noexcept - -> decltype(range(start, start, start)) { - // if step is < 0, stop is numeric min, otherwise numeric max - return range( - start, - step < T(0) ? std::numeric_limits::min() : - std::numeric_limits::max(), - step); - } + template + constexpr auto count(T start, T step) noexcept + -> decltype(range(start, start, start)) { + // if step is < 0, stop is numeric min, otherwise numeric max + return range(start, step < T(0) ? std::numeric_limits::min() + : std::numeric_limits::max(), + step); + } - template - constexpr auto count(T start =T(0)) noexcept - -> decltype(range(start, start)) { - return count(start, T(1)); - } + template + constexpr auto count(T start = T(0)) noexcept + -> decltype(range(start, start)) { + return count(start, T(1)); + } } - #endif diff --git a/cycle.hpp b/cycle.hpp index 42b86117..84e0c314 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -9,101 +9,91 @@ namespace iter { - template - class Cycle; + template + class Cycle; - template - Cycle cycle(Container&&); + template + Cycle cycle(Container&&); - template - Cycle> cycle(std::initializer_list); - - template - class Cycle { - private: - friend Cycle cycle(Container&&); - template - friend Cycle> cycle( - std::initializer_list); - - Container container; - - Cycle(Container&& in_container) - : container(std::forward(in_container)) - { } - - public: - class Iterator - : public std::iterator> - { - private: - using iter_type = iterator_type; - iterator_type sub_iter; - iterator_type begin; - iterator_type end; - public: - Iterator (const iterator_type& iter, - iterator_type&& in_end) - : sub_iter{iter}, - begin{iter}, - end{std::move(in_end)} - { } - - iterator_deref operator*() { - return *this->sub_iter; - } - - iterator_arrow operator->() { - return apply_arrow(this->sub_iter); - } - - Iterator& operator++() { - ++this->sub_iter; - // reset to beginning upon reaching the end - if (!(this->sub_iter != this->end)) { - this->sub_iter = this->begin; - } - 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 {std::begin(this->container), - std::end(this->container)}; - } - - Iterator end() { - return {std::end(this->container), - std::end(this->container)}; - } + template + Cycle> cycle(std::initializer_list); + template + class Cycle { + private: + friend Cycle cycle(Container&&); + template + friend Cycle> cycle(std::initializer_list); + + Container container; + + Cycle(Container&& in_container) + : container(std::forward(in_container)) {} + + public: + class Iterator : public std::iterator> { + private: + using iter_type = iterator_type; + iterator_type sub_iter; + iterator_type begin; + iterator_type end; + + public: + Iterator(const iterator_type& iter, + iterator_type&& in_end) + : sub_iter{iter}, begin{iter}, end{std::move(in_end)} {} + + iterator_deref operator*() { + return *this->sub_iter; + } + + iterator_arrow operator->() { + return apply_arrow(this->sub_iter); + } + + Iterator& operator++() { + ++this->sub_iter; + // reset to beginning upon reaching the end + if (!(this->sub_iter != this->end)) { + this->sub_iter = this->begin; + } + 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); + } }; - template - Cycle cycle(Container&& container) { - return {std::forward(container)}; + Iterator begin() { + return {std::begin(this->container), std::end(this->container)}; } - template - Cycle> cycle(std::initializer_list il) - { - return {std::move(il)}; + Iterator end() { + return {std::end(this->container), std::end(this->container)}; } + }; + + template + Cycle cycle(Container&& container) { + return {std::forward(container)}; + } + + template + Cycle> cycle(std::initializer_list il) { + return {std::move(il)}; + } } #endif diff --git a/dropwhile.hpp b/dropwhile.hpp index 7cdece67..073234de 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -9,129 +9,119 @@ namespace iter { - template - class DropWhile; - - template - DropWhile dropwhile(FilterFunc, Container&&); - - template - DropWhile> dropwhile( - FilterFunc, std::initializer_list); - - template - class DropWhile { - private: - Container container; - FilterFunc filter_func; - - friend DropWhile dropwhile( - FilterFunc, Container&&); - - template - friend DropWhile> dropwhile( - FF, std::initializer_list); - - DropWhile(FilterFunc in_filter_func, Container&& in_container) - : container(std::forward(in_container)), - filter_func(in_filter_func) - { } - - public: - class Iterator - : public std::iterator> - { - private: - using Holder = DerefHolder>; - iterator_type sub_iter; - iterator_type sub_end; - Holder item; - FilterFunc *filter_func; - - void inc_sub_iter() { - ++this->sub_iter; - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); - } - } - - // skip all values for which the predicate is true - void skip_passes() { - while (this->sub_iter != this->sub_end - && (*this->filter_func)(this->item.get())) { - this->inc_sub_iter(); - } - } - - public: - Iterator(iterator_type&& iter, - iterator_type&& end, - FilterFunc& in_filter_func) - : sub_iter{std::move(iter)}, - sub_end{std::move(end)}, - filter_func(&in_filter_func) - { - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); - } - this->skip_passes(); - } - - typename Holder::reference operator*() { - return this->item.get(); - } - - typename Holder::pointer operator->() { - return this->item.get_ptr(); - } - - Iterator& operator++() { - this->inc_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 {std::begin(this->container), - std::end(this->container), - this->filter_func}; - } - - Iterator end() { - return {std::end(this->container), - std::end(this->container), - this->filter_func}; - } - + template + class DropWhile; + + template + DropWhile dropwhile(FilterFunc, Container&&); + + template + DropWhile> dropwhile( + FilterFunc, std::initializer_list); + + template + class DropWhile { + private: + Container container; + FilterFunc filter_func; + + friend DropWhile dropwhile(FilterFunc, Container&&); + + template + friend DropWhile> dropwhile( + FF, std::initializer_list); + + DropWhile(FilterFunc in_filter_func, Container&& in_container) + : container(std::forward(in_container)), + filter_func(in_filter_func) {} + + public: + class Iterator : public std::iterator> { + private: + using Holder = DerefHolder>; + iterator_type sub_iter; + iterator_type sub_end; + Holder item; + FilterFunc* filter_func; + + void inc_sub_iter() { + ++this->sub_iter; + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); + } + } + + // skip all values for which the predicate is true + void skip_passes() { + while (this->sub_iter != this->sub_end + && (*this->filter_func)(this->item.get())) { + this->inc_sub_iter(); + } + } + + public: + Iterator(iterator_type&& iter, iterator_type&& end, + FilterFunc& in_filter_func) + : sub_iter{std::move(iter)}, + sub_end{std::move(end)}, + filter_func(&in_filter_func) { + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); + } + this->skip_passes(); + } + + typename Holder::reference operator*() { + return this->item.get(); + } + + typename Holder::pointer operator->() { + return this->item.get_ptr(); + } + + Iterator& operator++() { + this->inc_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); + } }; - template - DropWhile dropwhile( - FilterFunc filter_func, Container&& container) { - return {filter_func, std::forward(container)}; + Iterator begin() { + return {std::begin(this->container), std::end(this->container), + this->filter_func}; } - template - DropWhile> dropwhile( - FilterFunc filter_func, std::initializer_list il) - { - return {filter_func, std::move(il)}; + Iterator end() { + return {std::end(this->container), std::end(this->container), + this->filter_func}; } + }; + + template + DropWhile dropwhile( + FilterFunc filter_func, Container&& container) { + return {filter_func, std::forward(container)}; + } + + template + DropWhile> dropwhile( + FilterFunc filter_func, std::initializer_list il) { + return {filter_func, std::move(il)}; + } } #endif diff --git a/enumerate.hpp b/enumerate.hpp index e5df1ca9..c43996f7 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -11,111 +11,104 @@ namespace iter { - //Forward declarations of Enumerable and enumerate - template - class Enumerable; + // Forward declarations of Enumerable and enumerate + template + class Enumerable; - template - Enumerable enumerate(Container&&); + template + Enumerable enumerate(Container&&); + template + Enumerable> enumerate(std::initializer_list); + + template + class Enumerable { + private: + Container container; + + // The only thing allowed to directly instantiate an Enumerable is + // the enumerate function + friend Enumerable enumerate(Container&&); template - Enumerable> enumerate(std::initializer_list); - - template - class Enumerable { - private: - Container container; - - // The only thing allowed to directly instantiate an Enumerable is - // the enumerate function - friend Enumerable enumerate(Container&&); - template - friend Enumerable> enumerate( - std::initializer_list); - - // for IterYield - using BasePair = std::pair>; - - // Value constructor for use only in the enumerate function - Enumerable(Container&& in_container) - : container(std::forward(in_container)) - { } - - public: - // "yielded" by the Enumerable::Iterator. Has a .index, and a - // .element referencing the value yielded by the subiterator - class IterYield : public BasePair { - public: - using BasePair::BasePair; - typename BasePair::first_type& index = BasePair::first; - typename BasePair::second_type& element = BasePair::second; - }; - - // Holds an iterator of the contained type and a size_t for the - // index. Each call to ++ increments both of these data members. - // Each dereference returns an IterYield. - class Iterator : - public std::iterator - { - private: - iterator_type sub_iter; - std::size_t index; - public: - Iterator(iterator_type&& si) - : sub_iter{std::move(si)}, - index{0} - { } - - IterYield operator*() { - return {this->index, *this->sub_iter}; - } - - ArrowProxy operator->() { - return {**this}; - } - - Iterator& operator++() { - ++this->sub_iter; - ++this->index; - 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 {std::begin(this->container)}; - } - - Iterator end() { - return {std::end(this->container)}; - } + friend Enumerable> enumerate( + std::initializer_list); + + // for IterYield + using BasePair = std::pair>; + + // Value constructor for use only in the enumerate function + Enumerable(Container&& in_container) + : container(std::forward(in_container)) {} + + public: + // "yielded" by the Enumerable::Iterator. Has a .index, and a + // .element referencing the value yielded by the subiterator + class IterYield : public BasePair { + public: + using BasePair::BasePair; + typename BasePair::first_type& index = BasePair::first; + typename BasePair::second_type& element = BasePair::second; + }; + // Holds an iterator of the contained type and a size_t for the + // index. Each call to ++ increments both of these data members. + // Each dereference returns an IterYield. + class Iterator : public std::iterator { + private: + iterator_type sub_iter; + std::size_t index; + + public: + Iterator(iterator_type&& si) + : sub_iter{std::move(si)}, index{0} {} + + IterYield operator*() { + return {this->index, *this->sub_iter}; + } + + ArrowProxy operator->() { + return {**this}; + } + + Iterator& operator++() { + ++this->sub_iter; + ++this->index; + 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); + } }; - template - Enumerable enumerate(Container&& container) { - return {std::forward(container)}; + Iterator begin() { + return {std::begin(this->container)}; } - template - Enumerable> enumerate( - std::initializer_list il) - { - return {std::move(il)}; + Iterator end() { + return {std::end(this->container)}; } + }; + + template + Enumerable enumerate(Container&& container) { + return {std::forward(container)}; + } + + template + Enumerable> enumerate(std::initializer_list il) { + return {std::move(il)}; + } } #endif diff --git a/filter.hpp b/filter.hpp index 12801ed3..89e38531 100644 --- a/filter.hpp +++ b/filter.hpp @@ -9,175 +9,153 @@ namespace iter { - //Forward declarations of Filter and filter - template - class Filter; - - template - Filter filter(FilterFunc, Container&&); - - template - Filter> filter( - FilterFunc, std::initializer_list); - - template - class Filter { - private: - Container container; - FilterFunc filter_func; - - // The filter function is the only thing allowed to create a Filter - friend Filter filter( - FilterFunc, Container&&); - - template - friend Filter> filter( - FF, std::initializer_list); - - // Value constructor for use only in the filter function - Filter(FilterFunc in_filter_func, Container&& in_container) - : container(std::forward(in_container)), - filter_func(in_filter_func) - { } - - public: - - class Iterator - : public std::iterator> - { - protected: - using Holder = DerefHolder>; - iterator_type sub_iter; - iterator_type sub_end; - Holder item; - FilterFunc *filter_func; - - void inc_sub_iter() { - ++this->sub_iter; - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); - } - } - - // increment until the iterator points to is true on the - // predicate. Called by constructor and operator++ - void skip_failures() { - while (this->sub_iter != this->sub_end - && !(*this->filter_func)(this->item.get())) { - this->inc_sub_iter(); - } - } - - public: - Iterator (iterator_type iter, - iterator_type end, - FilterFunc& in_filter_func) - : sub_iter{iter}, - sub_end{end}, - filter_func(&in_filter_func) - { - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); - } - this->skip_failures(); - } - - typename Holder::reference operator*() { - return this->item.get(); - } - - typename Holder::pointer operator->() { - return this->item.get_ptr(); - } - - Iterator& operator++() { - this->inc_sub_iter(); - this->skip_failures(); - 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 {std::begin(this->container), - std::end(this->container), - this->filter_func}; - } - - Iterator end() { - return {std::end(this->container), - std::end(this->container), - this->filter_func}; - } - + // Forward declarations of Filter and filter + template + class Filter; + + template + Filter filter(FilterFunc, Container&&); + + template + Filter> filter( + FilterFunc, std::initializer_list); + + template + class Filter { + private: + Container container; + FilterFunc filter_func; + + // The filter function is the only thing allowed to create a Filter + friend Filter filter(FilterFunc, Container&&); + + template + friend Filter> filter( + FF, std::initializer_list); + + // Value constructor for use only in the filter function + Filter(FilterFunc in_filter_func, Container&& in_container) + : container(std::forward(in_container)), + filter_func(in_filter_func) {} + + public: + class Iterator : public std::iterator> { + protected: + using Holder = DerefHolder>; + iterator_type sub_iter; + iterator_type sub_end; + Holder item; + FilterFunc* filter_func; + + void inc_sub_iter() { + ++this->sub_iter; + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); + } + } + + // increment until the iterator points to is true on the + // predicate. Called by constructor and operator++ + void skip_failures() { + while (this->sub_iter != this->sub_end + && !(*this->filter_func)(this->item.get())) { + this->inc_sub_iter(); + } + } + + public: + Iterator(iterator_type iter, iterator_type end, + FilterFunc& in_filter_func) + : sub_iter{iter}, sub_end{end}, filter_func(&in_filter_func) { + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); + } + this->skip_failures(); + } + + typename Holder::reference operator*() { + return this->item.get(); + } + + typename Holder::pointer operator->() { + return this->item.get_ptr(); + } + + Iterator& operator++() { + this->inc_sub_iter(); + this->skip_failures(); + 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); + } }; - // Helper function to instantiate a Filter - template - Filter filter( - FilterFunc filter_func, Container&& container) { - return {filter_func, std::forward(container)}; + Iterator begin() { + return {std::begin(this->container), std::end(this->container), + this->filter_func}; } - template - Filter> filter( - FilterFunc filter_func, - std::initializer_list il) - { - return {filter_func, std::move(il)}; + Iterator end() { + return {std::end(this->container), std::end(this->container), + this->filter_func}; } + }; - namespace detail { - - template - bool boolean_cast(const T& t) { - return bool(t); - } - - template - class BoolTester { - public: - bool operator() (const iterator_deref item) const { - return bool(item); - } - }; - } + // Helper function to instantiate a Filter + template + Filter filter( + FilterFunc filter_func, Container&& container) { + return {filter_func, std::forward(container)}; + } + template + Filter> filter( + FilterFunc filter_func, std::initializer_list il) { + return {filter_func, std::move(il)}; + } - template - auto filter(Container&& container) -> - decltype(filter( - detail::BoolTester(), - std::forward(container))) { - return filter( - detail::BoolTester(), - std::forward(container)); - } + namespace detail { template - auto filter(std::initializer_list il) -> - decltype(filter( - detail::BoolTester>(), - std::move(il))) { - return filter( - detail::BoolTester>(), - std::move(il)); + bool boolean_cast(const T& t) { + return bool(t); } + template + class BoolTester { + public: + bool operator()(const iterator_deref item) const { + return bool(item); + } + }; + } + + template + auto filter(Container&& container) -> decltype(filter( + detail::BoolTester(), std::forward(container))) { + return filter( + detail::BoolTester(), std::forward(container)); + } + + template + auto filter(std::initializer_list il) -> decltype( + filter(detail::BoolTester>(), std::move(il))) { + return filter( + detail::BoolTester>(), std::move(il)); + } } #endif diff --git a/filterfalse.hpp b/filterfalse.hpp index 247fa84b..9d7d7840 100644 --- a/filterfalse.hpp +++ b/filterfalse.hpp @@ -8,98 +8,85 @@ namespace iter { - namespace detail { + namespace detail { - // Callable object that reverses the boolean result of another - // callable, taking the object in a Container's iterator - template - class PredicateFlipper { - private: - FilterFunc filter_func; - - public: - PredicateFlipper(FilterFunc in_filter_func) : - filter_func(in_filter_func) - { } - - PredicateFlipper() = delete; - PredicateFlipper(const PredicateFlipper&) = default; - - // Calls the filter_func - bool operator() (const iterator_deref item) const { - return !bool(filter_func(item)); - } - - // with non-const incase FilterFunc::operator() is non-const - bool operator() (const iterator_deref item) { - return !bool(filter_func(item)); - } - }; - - // Reverses the bool() conversion result of anything that supports a - // bool conversion - template - class BoolFlipper { - public: - bool operator() (const iterator_deref item) const { - return !bool(item); - } - }; - - - } - - // Creates a PredicateFlipper for the predicate function, which reverses - // the bool result of the function. The PredicateFlipper is then passed - // to the normal filter() function + // Callable object that reverses the boolean result of another + // callable, taking the object in a Container's iterator template - auto filterfalse(FilterFunc filter_func, Container&& container) -> - decltype(filter( - detail::PredicateFlipper( - filter_func), - std::forward(container))) { - return filter( - detail::PredicateFlipper(filter_func), - std::forward(container)); - } - - // Single argument version, uses a BoolFlipper to reverse the truthiness - // of an object + class PredicateFlipper { + private: + FilterFunc filter_func; + + public: + PredicateFlipper(FilterFunc in_filter_func) + : filter_func(in_filter_func) {} + + PredicateFlipper() = delete; + PredicateFlipper(const PredicateFlipper&) = default; + + // Calls the filter_func + bool operator()(const iterator_deref item) const { + return !bool(filter_func(item)); + } + + // with non-const incase FilterFunc::operator() is non-const + bool operator()(const iterator_deref item) { + return !bool(filter_func(item)); + } + }; + + // Reverses the bool() conversion result of anything that supports a + // bool conversion template - auto filterfalse(Container&& container) -> - decltype(filter( - detail::BoolFlipper(), - std::forward(container))) { - return filter( - detail::BoolFlipper(), - std::forward(container)); - } - - - - //specializations for initializer_lists - template - auto filterfalse(FilterFunc filter_func, std::initializer_list container) -> - decltype(filter( - detail::PredicateFlipper>( - filter_func), - std::move(container))) { - return filter( - 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))) { - return filter( - detail::BoolFlipper>(), - std::move(container)); - } + class BoolFlipper { + public: + bool operator()(const iterator_deref item) const { + return !bool(item); + } + }; + } + + // Creates a PredicateFlipper for the predicate function, which reverses + // 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))) { + return filter(detail::PredicateFlipper(filter_func), + std::forward(container)); + } + + // 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))) { + return filter( + detail::BoolFlipper(), std::forward(container)); + } + + // specializations for initializer_lists + template + auto filterfalse(FilterFunc filter_func, std::initializer_list container) + -> decltype( + filter(detail::PredicateFlipper>( + filter_func), + std::move(container))) { + return filter( + 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))) { + return filter( + detail::BoolFlipper>(), std::move(container)); + } } #endif diff --git a/groupby.hpp b/groupby.hpp index e238373f..c6d758a1 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -13,336 +13,301 @@ namespace iter { - template - class GroupBy; - - template - GroupBy groupby(Container&&, KeyFunc); - - template - GroupBy, KeyFunc> groupby( - std::initializer_list, KeyFunc); - - template - class GroupBy { - private: - Container container; - KeyFunc key_func; - - friend GroupBy groupby(Container&&, KeyFunc); - - template - friend GroupBy, KF> groupby( - std::initializer_list, KF); - - using key_func_ret = typename - std::result_of)>::type; - - GroupBy(Container&& in_container, KeyFunc in_key_func) - : container(std::forward(in_container)), - key_func(in_key_func) - { } - - public: - GroupBy() = delete; - GroupBy(const GroupBy&) = delete; - GroupBy& operator=(const GroupBy&) = delete; - GroupBy& operator=(GroupBy&&) = delete; - - GroupBy(GroupBy&&) = default; - - class Iterator; - class Group; - - private: - using KeyGroupPair = - std::pair; - using Holder = DerefHolder>; - public: - - class Iterator - : public std::iterator - { - private: - iterator_type sub_iter; - iterator_type sub_end; - Holder item; - KeyFunc *key_func; - - std::unique_ptr current_key_group_pair; - - public: - Iterator(iterator_type&& si, - iterator_type&& end, - KeyFunc& in_key_func) - : sub_iter{std::move(si)}, - sub_end{std::move(end)}, - key_func(&in_key_func) - { - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); - } - } - - Iterator(const Iterator& other) - : sub_iter{other.sub_iter}, - sub_end{other.sub_end}, - item{other.item}, - key_func{other.key_func} - { } - - Iterator& operator=(const Iterator& other) { - if (this == &other) return *this; - this->sub_iter = other.sub_iter; - this->sub_end = other.sub_end; - this->item = other.item; - this->key_func = other.key_func; - this->current_key_group_pair.reset(); - return *this; - } - - ~Iterator() =default; - - // NOTE the implicitly generated move constructor would - // be wrong - - KeyGroupPair& operator*() { - set_key_group_pair(); - return *this->current_key_group_pair; - } - - KeyGroupPair *operator->() { - set_key_group_pair(); - return this->current_key_group_pair.get(); - } - - Iterator& operator++() { - if (!this->current_key_group_pair) { - this->set_key_group_pair(); - } - this->current_key_group_pair.reset(); - 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); - } - - void increment_iterator() { - if (this->sub_iter != this->sub_end) { - ++this->sub_iter; - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); - } - } - } - - bool exhausted() const { - return !(this->sub_iter != this->sub_end); - } - - typename Holder::reference get() { - return this->item.get(); - } - - typename Holder::pointer get_ptr() { - return this->item.get_ptr(); - } - - key_func_ret next_key() { - return (*this->key_func)(this->item.get()); - } - - void set_key_group_pair() { - if (!this->current_key_group_pair) { - this->current_key_group_pair.reset( - new KeyGroupPair( - (*this->key_func)(this->item.get()), - Group{*this, this->next_key()})); - } - } - - }; - - - class Group { - private: - friend Iterator; - friend class GroupIterator; - Iterator& owner; - key_func_ret key; - - // completed is set if a Group is iterated through - // completely. It is checked in the destructor, and - // if the Group has not been completed, the destructor - // exhausts it. This ensures that the next Group starts - // at the correct position when the user short-circuits - // iteration over a Group. - // The move constructor sets the rvalue's completed - // attribute to true, so its destructor doesn't do anything - // when called. - bool completed = false; - - Group(Iterator& in_owner, key_func_ret in_key) : - owner(in_owner), - key(in_key) - { } - - public: - ~Group() { - if (!this->completed) { - for (auto iter = this->begin(), end = this->end(); - iter != end; - ++iter) { } - } - } - - // move-constructible, non-copy-constructible, - // non-assignable - Group() = delete; - Group(const Group&) = default; - Group& operator=(const Group&) = delete; - Group& operator=(Group&&) = delete; - - Group(Group&& other) - : owner{other.owner}, - key{other.key}, - completed{other.completed} { - other.completed = true; - } - - class GroupIterator - : public std::iterator> - { - private: - typename std::remove_reference::type *key; - Group *group_p; - - bool not_at_end() { - return !this->group_p->owner.exhausted()&& - this->group_p->owner.next_key() == *this->key; - } - - public: - GroupIterator(Group *in_group_p, - key_func_ret& in_key) - : key{&in_key}, - group_p{in_group_p} - { } - - bool operator!=(const GroupIterator& other) const { - return !(*this == other); - } - - bool operator==(const GroupIterator& other) const { - return this->group_p == other.group_p; - } - - GroupIterator& operator++() { - this->group_p->owner.increment_iterator(); - if (!this->not_at_end()) { - this->group_p->completed = true; - this->group_p = nullptr; - } - return *this; - } - - GroupIterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - iterator_deref operator*() { - return this->group_p->owner.get(); - } - - typename Holder::pointer operator->() { - return this->group_p->owner.get_ptr(); - } - }; - - GroupIterator begin() { - return {this, key}; - } - - GroupIterator end() { - return {nullptr, key}; - } - - }; - - - Iterator begin() { - return {std::begin(this->container), - std::end(this->container), - this->key_func}; - } - - Iterator end() { - return {std::end(this->container), - std::end(this->container), - this->key_func}; - } - + template + class GroupBy; + + template + GroupBy groupby(Container&&, KeyFunc); + + template + GroupBy, KeyFunc> groupby( + std::initializer_list, KeyFunc); + + template + class GroupBy { + private: + Container container; + KeyFunc key_func; + + friend GroupBy groupby(Container&&, KeyFunc); + + template + friend GroupBy, KF> groupby( + std::initializer_list, KF); + + using key_func_ret = + typename std::result_of)>::type; + + GroupBy(Container&& in_container, KeyFunc in_key_func) + : container(std::forward(in_container)), + key_func(in_key_func) {} + + public: + GroupBy() = delete; + GroupBy(const GroupBy&) = delete; + GroupBy& operator=(const GroupBy&) = delete; + GroupBy& operator=(GroupBy&&) = delete; + + GroupBy(GroupBy&&) = default; + + class Iterator; + class Group; + + private: + using KeyGroupPair = std::pair; + using Holder = DerefHolder>; + + public: + class Iterator + : public std::iterator { + private: + iterator_type sub_iter; + iterator_type sub_end; + Holder item; + KeyFunc* key_func; + + std::unique_ptr current_key_group_pair; + + public: + Iterator(iterator_type&& si, iterator_type&& end, + KeyFunc& in_key_func) + : sub_iter{std::move(si)}, + sub_end{std::move(end)}, + key_func(&in_key_func) { + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); + } + } + + Iterator(const Iterator& other) + : sub_iter{other.sub_iter}, + sub_end{other.sub_end}, + item{other.item}, + key_func{other.key_func} {} + + Iterator& operator=(const Iterator& other) { + if (this == &other) return *this; + this->sub_iter = other.sub_iter; + this->sub_end = other.sub_end; + this->item = other.item; + this->key_func = other.key_func; + this->current_key_group_pair.reset(); + return *this; + } + + ~Iterator() = default; + + // NOTE the implicitly generated move constructor would + // be wrong + + KeyGroupPair& operator*() { + set_key_group_pair(); + return *this->current_key_group_pair; + } + + KeyGroupPair* operator->() { + set_key_group_pair(); + return this->current_key_group_pair.get(); + } + + Iterator& operator++() { + if (!this->current_key_group_pair) { + this->set_key_group_pair(); + } + this->current_key_group_pair.reset(); + 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); + } + + void increment_iterator() { + if (this->sub_iter != this->sub_end) { + ++this->sub_iter; + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); + } + } + } + + bool exhausted() const { + return !(this->sub_iter != this->sub_end); + } + + typename Holder::reference get() { + return this->item.get(); + } + + typename Holder::pointer get_ptr() { + return this->item.get_ptr(); + } + + key_func_ret next_key() { + return (*this->key_func)(this->item.get()); + } + + void set_key_group_pair() { + if (!this->current_key_group_pair) { + this->current_key_group_pair.reset( + new KeyGroupPair((*this->key_func)(this->item.get()), + Group{*this, this->next_key()})); + } + } }; - // Takes something and returns it, used for default key of comparing - // items in the sequence directly - template - class ItemReturner { - public: - iterator_deref operator() ( - iterator_deref item) const { - return item; - } + class Group { + private: + friend Iterator; + friend class GroupIterator; + Iterator& owner; + key_func_ret key; + + // completed is set if a Group is iterated through + // completely. It is checked in the destructor, and + // if the Group has not been completed, the destructor + // exhausts it. This ensures that the next Group starts + // at the correct position when the user short-circuits + // iteration over a Group. + // The move constructor sets the rvalue's completed + // attribute to true, so its destructor doesn't do anything + // when called. + bool completed = false; + + Group(Iterator& in_owner, key_func_ret in_key) + : owner(in_owner), key(in_key) {} + + public: + ~Group() { + if (!this->completed) { + for (auto iter = this->begin(), end = this->end(); iter != end; + ++iter) { + } + } + } + + // move-constructible, non-copy-constructible, + // non-assignable + Group() = delete; + Group(const Group&) = default; + Group& operator=(const Group&) = delete; + Group& operator=(Group&&) = delete; + + Group(Group&& other) + : owner{other.owner}, key{other.key}, completed{other.completed} { + other.completed = true; + } + + class GroupIterator : public std::iterator> { + private: + typename std::remove_reference::type* key; + Group* group_p; + + bool not_at_end() { + return !this->group_p->owner.exhausted() + && this->group_p->owner.next_key() == *this->key; + } + + public: + GroupIterator(Group* in_group_p, key_func_ret& in_key) + : key{&in_key}, group_p{in_group_p} {} + + bool operator!=(const GroupIterator& other) const { + return !(*this == other); + } + + bool operator==(const GroupIterator& other) const { + return this->group_p == other.group_p; + } + + GroupIterator& operator++() { + this->group_p->owner.increment_iterator(); + if (!this->not_at_end()) { + this->group_p->completed = true; + this->group_p = nullptr; + } + return *this; + } + + GroupIterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + iterator_deref operator*() { + return this->group_p->owner.get(); + } + + typename Holder::pointer operator->() { + return this->group_p->owner.get_ptr(); + } + }; + + GroupIterator begin() { + return {this, key}; + } + + GroupIterator end() { + return {nullptr, key}; + } }; - - template - GroupBy groupby( - Container&& container, KeyFunc key_func) { - return {std::forward(container), key_func}; + Iterator begin() { + return {std::begin(this->container), std::end(this->container), + this->key_func}; } - - template - auto groupby(Container&& container) -> - decltype(groupby(std::forward(container), - ItemReturner())) { - return groupby(std::forward(container), - ItemReturner()); + Iterator end() { + return { + std::end(this->container), std::end(this->container), this->key_func}; } - - - template - GroupBy, KeyFunc> groupby( - std::initializer_list il, KeyFunc key_func) { - return {std::move(il), key_func}; + }; + + // Takes something and returns it, used for default key of comparing + // items in the sequence directly + template + class ItemReturner { + public: + iterator_deref operator()(iterator_deref item) const { + return item; } - - - template - auto groupby(std::initializer_list il) -> - decltype(groupby(std::move(il), - ItemReturner>())) { - return groupby( - std::move(il), - ItemReturner>()); - } - + }; + + template + GroupBy groupby(Container&& container, KeyFunc key_func) { + return {std::forward(container), key_func}; + } + + template + auto groupby(Container&& container) -> decltype( + groupby(std::forward(container), ItemReturner())) { + return groupby( + std::forward(container), ItemReturner()); + } + + template + GroupBy, KeyFunc> groupby( + std::initializer_list il, KeyFunc key_func) { + return {std::move(il), key_func}; + } + + template + auto groupby(std::initializer_list il) -> decltype( + groupby(std::move(il), ItemReturner>())) { + return groupby(std::move(il), ItemReturner>()); + } } - #endif diff --git a/grouper.hpp b/grouper.hpp index d3bebcdf..0c6abd09 100644 --- a/grouper.hpp +++ b/grouper.hpp @@ -13,124 +13,113 @@ #include namespace iter { - template - class Grouper; + template + class Grouper; - template - Grouper grouper(Container&&, std::size_t); + template + Grouper grouper(Container&&, std::size_t); + template + Grouper> grouper( + std::initializer_list, std::size_t); + + template + class Grouper { + private: + Container container; + std::size_t group_size; + + Grouper(Container&& c, std::size_t sz) + : container(std::forward(c)), group_size{sz} {} + + friend Grouper grouper(Container&&, std::size_t); template - Grouper> grouper( - std::initializer_list, std::size_t); - - template - class Grouper { - private: - Container container; - std::size_t group_size; - - Grouper(Container&& c, std::size_t sz) - : container(std::forward(c)), - group_size{sz} - { } - - friend Grouper grouper(Container&&, std::size_t); - template - friend Grouper> grouper( - std::initializer_list, std::size_t); - - using IndexVector = std::vector>; - using DerefVec = IterIterWrapper; - public: - class Iterator : - public std::iterator - { - private: - iterator_type sub_iter; - iterator_type sub_end; - DerefVec group; - std::size_t group_size = 0; - - bool done() const { - return this->group.empty(); - } - - void refill_group() { - this->group.get().clear(); - std::size_t i{0}; - while (i < group_size - && this->sub_iter != this->sub_end) { - group.get().push_back(this->sub_iter); - ++this->sub_iter; - ++i; - } - } - - public: - Iterator(iterator_type&& in_iter, - iterator_type&& in_end, - std::size_t s) - : sub_iter{std::move(in_iter)}, - sub_end{std::move(in_end)}, - group_size{s} - { - this->group.get().reserve(this->group_size); - this->refill_group(); - } - - Iterator& operator++() { - this->refill_group(); - return *this; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - bool operator!=(const Iterator& other) const { - return !(*this == other); - } - - bool operator==(const Iterator& other) const { - return this->done() == other.done() - && (this->done() - || !(this->sub_iter != other.sub_iter)); - } - - - DerefVec& operator*() { - return this->group; - } - - DerefVec *operator->() { - return &this->group; - } - }; - - Iterator begin() { - return {std::begin(this->container), - std::end(this->container), - group_size}; - } - - Iterator end() { - return {std::end(this->container), - std::end(this->container), - group_size}; - } + friend Grouper> grouper( + std::initializer_list, std::size_t); + + using IndexVector = std::vector>; + using DerefVec = IterIterWrapper; + + public: + class Iterator : public std::iterator { + private: + iterator_type sub_iter; + iterator_type sub_end; + DerefVec group; + std::size_t group_size = 0; + + bool done() const { + return this->group.empty(); + } + + void refill_group() { + this->group.get().clear(); + std::size_t i{0}; + while (i < group_size && this->sub_iter != this->sub_end) { + group.get().push_back(this->sub_iter); + ++this->sub_iter; + ++i; + } + } + + public: + Iterator(iterator_type&& in_iter, + iterator_type&& in_end, std::size_t s) + : sub_iter{std::move(in_iter)}, + sub_end{std::move(in_end)}, + group_size{s} { + this->group.get().reserve(this->group_size); + this->refill_group(); + } + + Iterator& operator++() { + this->refill_group(); + return *this; + } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + bool operator!=(const Iterator& other) const { + return !(*this == other); + } + + bool operator==(const Iterator& other) const { + return this->done() == other.done() + && (this->done() || !(this->sub_iter != other.sub_iter)); + } + + DerefVec& operator*() { + return this->group; + } + + DerefVec* operator->() { + return &this->group; + } }; - template - Grouper grouper(Container&& container, std::size_t group_size) { - return {std::forward(container), group_size}; + Iterator begin() { + return { + std::begin(this->container), std::end(this->container), group_size}; } - template - Grouper> grouper( - std::initializer_list il, std::size_t group_size) { - return {std::move(il), group_size}; + Iterator end() { + return {std::end(this->container), std::end(this->container), group_size}; } + }; + + template + Grouper grouper(Container&& container, std::size_t group_size) { + return {std::forward(container), group_size}; + } + + template + Grouper> grouper( + std::initializer_list il, std::size_t group_size) { + return {std::move(il), group_size}; + } } #endif diff --git a/imap.hpp b/imap.hpp index cbe7174c..c65a7035 100644 --- a/imap.hpp +++ b/imap.hpp @@ -9,154 +9,136 @@ namespace iter { - namespace detail { + 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::forward< - typename std::tuple_element::type>::type>( - std::get(tup)), - std::forward(args)...)) - { - // recurse - return Expander::call( - std::forward(f), - std::forward(tup), - // pull out one element - std::forward< - typename std::tuple_element::type>::type>( - std::get(tup)), - std::forward(args)...); // everything already expanded - } + template + static auto call(Functor&& f, Tup&& tup, Ts&&... args) + -> decltype(Expander::call( + std::forward(f), std::forward(tup), + std::forward::type>::type>( + std::get(tup)), + std::forward(args)...)) { + // recurse + return Expander::call( + std::forward(f), std::forward(tup), + // pull out one element + std::forward::type>::type>( + std::get(tup)), + std::forward(args)...); // everything already expanded + } }; 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 + static auto call(Functor&& f, Tup&&, Ts&&... args) + -> decltype(f(std::forward(args)...)) { + static_assert( + std::tuple_size::type>::value + == sizeof...(Ts), + "tuple has not been fully expanded"); + return f(std::forward(args)...); // the actual call + } }; 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)); + 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; - - 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; - - using IMapIterDeref = decltype(detail::call_with_tuple( - map_func, *std::begin(zipped))); - - // Value constructor for use only in the imap function - IMap(MapFunc in_map_func, Containers&&... in_containers) : - map_func(in_map_func), - zipped(zip(std::forward(in_containers)...)) - { } - - public: - class Iterator - : public std::iterator::type > - { - private: - MapFunc *map_func; - ZippedIterType zipiter; - - public: - Iterator(MapFunc& in_map_func, ZippedIterType&& in_zipiter) - : map_func(&in_map_func), - zipiter(std::move(in_zipiter)) - { } - - IMapIterDeref operator*() { - return detail::call_with_tuple( - *this->map_func, *(this->zipiter)); - } - - ArrowProxy operator->() { - return {**this}; - } - - Iterator& operator++() { - ++this->zipiter; - return *this; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - bool operator!=(const Iterator& other) const { - return this->zipiter != other.zipiter; - } - - bool operator==(const Iterator& other) const { - return !(*this != other); - } - }; - - Iterator begin() { - return {this->map_func, this->zipped.begin()}; - } - - Iterator end() { - return {this->map_func, this->zipped.end()}; - } + } // end detail + // 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; + + using IMapIterDeref = + decltype(detail::call_with_tuple(map_func, *std::begin(zipped))); + + // Value constructor for use only in the imap function + IMap(MapFunc in_map_func, Containers&&... in_containers) + : map_func(in_map_func), + zipped(zip(std::forward(in_containers)...)) {} + + public: + class Iterator : public std::iterator::type> { + private: + MapFunc* map_func; + ZippedIterType zipiter; + + public: + Iterator(MapFunc& in_map_func, ZippedIterType&& in_zipiter) + : map_func(&in_map_func), zipiter(std::move(in_zipiter)) {} + + IMapIterDeref operator*() { + return detail::call_with_tuple(*this->map_func, *(this->zipiter)); + } + + ArrowProxy operator->() { + return {**this}; + } + + Iterator& operator++() { + ++this->zipiter; + return *this; + } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + bool operator!=(const Iterator& other) const { + return this->zipiter != other.zipiter; + } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } }; - // Helper function to instantiate a IMap - template - IMap imap( - MapFunc map_func, Containers&& ... containers) { - return {map_func, std::forward(containers)...}; + 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)...}; + } } -#endif // #ifndef ITER_IMAP_H_ +#endif // #ifndef ITER_IMAP_H_ diff --git a/iteratoriterator.hpp b/iteratoriterator.hpp index bf4fc35b..ad330c6c 100644 --- a/iteratoriterator.hpp +++ b/iteratoriterator.hpp @@ -15,273 +15,254 @@ // behave like some_collection when iterated over or indexed namespace iter { - template - struct HasConstDeref : std::false_type { }; - - template - struct HasConstDeref())>> - : std::true_type { }; - - template ::difference_type> - class IteratorIterator : public std::iterator< - std::random_access_iterator_tag, - typename std::iterator_traits::value_type, - Diff, - typename std::iterator_traits::pointer, - typename std::iterator_traits::reference - > - { - static_assert(std::is_same< - typename std::iterator_traits::iterator_category, + template + struct HasConstDeref : std::false_type {}; + + template + struct HasConstDeref())>> + : std::true_type {}; + + template ::difference_type> + class IteratorIterator + : public std::iterator::value_type, Diff, + typename std::iterator_traits::pointer, + typename std::iterator_traits::reference> { + static_assert( + std::is_same::iterator_category, std::random_access_iterator_tag>::value, - "IteratorIterator only works with random access iterators"); - private: - Iter sub_iter; - public: - IteratorIterator() = default; - IteratorIterator(const Iter& it) - : sub_iter{it} - { } - - bool operator==(const IteratorIterator& other) const { - return !(*this != other); - } - - bool operator!=(const IteratorIterator& other) const { - return this->sub_iter != other.sub_iter; - } - - IteratorIterator& operator++() { - ++this->sub_iter; - return *this; - } - - IteratorIterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - IteratorIterator& operator--() { - --this->sub_iter; - return *this; - } - - IteratorIterator operator--(int) { - auto ret = *this; - --*this; - return ret; - } - - auto operator*() -> decltype(**sub_iter) { - return **this->sub_iter; - } - - auto operator->() -> decltype(*sub_iter) { - return *this->sub_iter; - } - - - IteratorIterator& operator+=(Diff n) { - this->sub_iter += n; - return *this; - } - - IteratorIterator operator+(Diff n) const { - auto it = *this; - it += n; - return it; - } - - friend IteratorIterator operator+(Diff n, IteratorIterator it) { - it += n; - return it; - } - - IteratorIterator& operator-=(Diff n) { - this->sub_iter -= n; - return *this; - } - - IteratorIterator operator-(Diff n) const { - auto it = *this; - it -= n; - return it; - } - - friend IteratorIterator operator-(Diff n, IteratorIterator it) { - it -= n; - return it; - } - - Diff operator-(const IteratorIterator& rhs) const { - return this->sub_iter - rhs.sub_iter; - } - - auto operator[](Diff idx) -> decltype(*sub_iter[idx]) { - return *sub_iter[idx]; - } - - bool operator<(const IteratorIterator& rhs) const { - return this->sub_iter < rhs.sub_iter; - } - - bool operator>(const IteratorIterator& rhs) const { - return this->sub_iter > rhs.sub_iter; - } - - bool operator<=(const IteratorIterator& rhs) const { - return this->sub_iter <= rhs.sub_iter; - } - - bool operator>=(const IteratorIterator& rhs) const { - return this->sub_iter >= rhs.sub_iter; - } - }; - - template - class IterIterWrapper { - private: - Container container; - - using contained_iter = typename Container::value_type; - using size_type = typename Container::size_type; - using iterator = - IteratorIterator; - using const_iterator = - IteratorIterator; - using reverse_iterator = - IteratorIterator; - using const_reverse_iterator = - IteratorIterator; - - template - struct ConstAtTypeOrVoid : type_is { }; - - template - struct ConstAtTypeOrVoid < - U, void_t().at(0))>> - : type_is().at(0))> - { }; - - using const_at_type_or_void_t = typename ConstAtTypeOrVoid<>::type; - - template - struct ConstIndexTypeOrVoid : type_is { }; - - template - struct ConstIndexTypeOrVoid < - U, void_t()[0])>> - : type_is()[0])> - { }; - - using const_index_type_or_void_t = - typename ConstIndexTypeOrVoid<>::type; - - public: - IterIterWrapper() = default; - - explicit IterIterWrapper(size_type sz) - : container(sz) - { } - - IterIterWrapper(size_type sz, const contained_iter& val) - : container(sz, val) - { } - - auto at(size_type pos) -> decltype(*container.at(pos)) { - return *container.at(pos); - } - - auto at(size_type pos) const -> - const_at_type_or_void_t - { - return *container.at(pos); - } - - auto operator[](size_type pos) - noexcept(noexcept(*container[pos])) - -> decltype(*container[pos]) - { - return *container[pos]; - } - - auto operator[](size_type pos) const - noexcept(noexcept(*container[pos])) - -> const_index_type_or_void_t - { - return *container[pos]; - } - - bool empty() const noexcept { - return container.empty(); - } - - size_type size() const noexcept { - return container.size(); - } - - iterator begin() noexcept { - return {container.begin()}; - } - - iterator end() noexcept { - return {container.end()}; - } - - const_iterator begin() const noexcept { - return {container.begin()}; - } - - const_iterator end() const noexcept { - return {container.end()}; - } - - const_iterator cbegin() const noexcept { - return {container.cbegin()}; - } - - const_iterator cend() const noexcept { - return {container.cend()}; - } - - reverse_iterator rbegin() noexcept { - return {container.rbegin()}; - } - - reverse_iterator rend() noexcept { - return {container.rend()}; - } - - const_reverse_iterator rbegin() const noexcept { - return {container.rbegin()}; - } - - const_reverse_iterator rend() const noexcept { - return {container.rend()}; - } - - const_reverse_iterator crbegin() const noexcept { - return {container.rbegin()}; - } - - const_reverse_iterator crend() const noexcept { - return {container.rend()}; - } - - // get() exposes the underlying container. this allows the - // itertools to manipulate the iterators in the container - // and should not be depended on anywhere else. - Container& get() noexcept { - return container; - } - - const Container& get() const noexcept { - return container; - } - - }; + "IteratorIterator only works with random access iterators"); + + private: + Iter sub_iter; + + public: + IteratorIterator() = default; + IteratorIterator(const Iter& it) : sub_iter{it} {} + + bool operator==(const IteratorIterator& other) const { + return !(*this != other); + } + + bool operator!=(const IteratorIterator& other) const { + return this->sub_iter != other.sub_iter; + } + + IteratorIterator& operator++() { + ++this->sub_iter; + return *this; + } + + IteratorIterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + IteratorIterator& operator--() { + --this->sub_iter; + return *this; + } + + IteratorIterator operator--(int) { + auto ret = *this; + --*this; + return ret; + } + + auto operator*() -> decltype(**sub_iter) { + return **this->sub_iter; + } + + auto operator-> () -> decltype(*sub_iter) { + return *this->sub_iter; + } + + IteratorIterator& operator+=(Diff n) { + this->sub_iter += n; + return *this; + } + + IteratorIterator operator+(Diff n) const { + auto it = *this; + it += n; + return it; + } + + friend IteratorIterator operator+(Diff n, IteratorIterator it) { + it += n; + return it; + } + + IteratorIterator& operator-=(Diff n) { + this->sub_iter -= n; + return *this; + } + + IteratorIterator operator-(Diff n) const { + auto it = *this; + it -= n; + return it; + } + + friend IteratorIterator operator-(Diff n, IteratorIterator it) { + it -= n; + return it; + } + + Diff operator-(const IteratorIterator& rhs) const { + return this->sub_iter - rhs.sub_iter; + } + + auto operator[](Diff idx) -> decltype(*sub_iter[idx]) { + return *sub_iter[idx]; + } + + bool operator<(const IteratorIterator& rhs) const { + return this->sub_iter < rhs.sub_iter; + } + + bool operator>(const IteratorIterator& rhs) const { + return this->sub_iter > rhs.sub_iter; + } + + bool operator<=(const IteratorIterator& rhs) const { + return this->sub_iter <= rhs.sub_iter; + } + + bool operator>=(const IteratorIterator& rhs) const { + return this->sub_iter >= rhs.sub_iter; + } + }; + + template + class IterIterWrapper { + private: + Container container; + + using contained_iter = typename Container::value_type; + using size_type = typename Container::size_type; + using iterator = IteratorIterator; + using const_iterator = IteratorIterator; + using reverse_iterator = + IteratorIterator; + using const_reverse_iterator = + IteratorIterator; + + template + struct ConstAtTypeOrVoid : type_is {}; + + template + struct ConstAtTypeOrVoid().at(0))>> + : type_is().at(0))> {}; + + using const_at_type_or_void_t = typename ConstAtTypeOrVoid<>::type; + + template + struct ConstIndexTypeOrVoid : type_is {}; + + template + struct ConstIndexTypeOrVoid()[0])>> + : type_is()[0])> {}; + + using const_index_type_or_void_t = typename ConstIndexTypeOrVoid<>::type; + + public: + IterIterWrapper() = default; + + explicit IterIterWrapper(size_type sz) : container(sz) {} + + IterIterWrapper(size_type sz, const contained_iter& val) + : container(sz, val) {} + + auto at(size_type pos) -> decltype(*container.at(pos)) { + return *container.at(pos); + } + + auto at(size_type pos) const -> const_at_type_or_void_t { + return *container.at(pos); + } + + auto operator[](size_type pos) noexcept(noexcept(*container[pos])) + -> decltype(*container[pos]) { + return *container[pos]; + } + + auto operator[](size_type pos) const noexcept(noexcept(*container[pos])) + -> const_index_type_or_void_t { + return *container[pos]; + } + + bool empty() const noexcept { + return container.empty(); + } + + size_type size() const noexcept { + return container.size(); + } + + iterator begin() noexcept { + return {container.begin()}; + } + + iterator end() noexcept { + return {container.end()}; + } + + const_iterator begin() const noexcept { + return {container.begin()}; + } + + const_iterator end() const noexcept { + return {container.end()}; + } + + const_iterator cbegin() const noexcept { + return {container.cbegin()}; + } + + const_iterator cend() const noexcept { + return {container.cend()}; + } + + reverse_iterator rbegin() noexcept { + return {container.rbegin()}; + } + + reverse_iterator rend() noexcept { + return {container.rend()}; + } + + const_reverse_iterator rbegin() const noexcept { + return {container.rbegin()}; + } + + const_reverse_iterator rend() const noexcept { + return {container.rend()}; + } + + const_reverse_iterator crbegin() const noexcept { + return {container.rbegin()}; + } + + const_reverse_iterator crend() const noexcept { + return {container.rend()}; + } + + // get() exposes the underlying container. this allows the + // itertools to manipulate the iterators in the container + // and should not be depended on anywhere else. + Container& get() noexcept { + return container; + } + + const Container& get() const noexcept { + return container; + } + }; } #endif diff --git a/iterbase.hpp b/iterbase.hpp index cc195a0e..20585a7a 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -1,7 +1,6 @@ #ifndef ITERBASE_HPP_ #define ITERBASE_HPP_ - // This file consists of utilities used for the generic nature of the // iterable wrapper classes. As such, the contents of this file should be // considered UNDOCUMENTED and is subject to change without warning. This @@ -16,285 +15,268 @@ #include namespace iter { - template - struct type_is { - using type = T; - }; - - // gcc CWG 1558 - template - struct void_t_help { - using type = void; - }; - template - using void_t = typename void_t_help::type; - - - // iterator_type is the type of C's iterator - template - using iterator_type = - decltype(std::begin(std::declval())); - - // iterator_deref is the type obtained by dereferencing an iterator - // to an object of type C - template - using iterator_deref = - decltype(*std::declval&>()); - - // const_iteator_deref is the type obtained through dereferencing - // a const iterator& (note: not a const_iterator). ie: the result - // of Container::iterator::operator*() const - template - using const_iterator_deref = - decltype(*std::declval&>()); - - - template - using iterator_traits_deref = - typename std::remove_reference>::type; - - // iterator_type is the type of C's iterator - template - using reverse_iterator_type = - decltype(std::declval().rbegin()); - - // iterator_deref is the type obtained by dereferencing an iterator - // to an object of type C - template - using reverse_iterator_deref = - decltype(*std::declval&>()); - - namespace detail { - template + template + struct type_is { + using type = T; + }; + + // gcc CWG 1558 + template + struct void_t_help { + using type = void; + }; + template + using void_t = typename void_t_help::type; + + // iterator_type is the type of C's iterator + template + using iterator_type = decltype(std::begin(std::declval())); + + // iterator_deref is the type obtained by dereferencing an iterator + // to an object of type C + template + using iterator_deref = decltype(*std::declval&>()); + + // const_iteator_deref is the type obtained through dereferencing + // a const iterator& (note: not a const_iterator). ie: the result + // of Container::iterator::operator*() const + template + using const_iterator_deref = + decltype(*std::declval&>()); + + template + using iterator_traits_deref = + typename std::remove_reference>::type; + + // iterator_type is the type of C's iterator + template + using reverse_iterator_type = decltype(std::declval().rbegin()); + + // iterator_deref is the type obtained by dereferencing an iterator + // to an object of type C + template + using reverse_iterator_deref = + decltype(*std::declval&>()); + + namespace detail { + template struct ArrowHelper { - using type = void; + using type = void; }; template struct ArrowHelper { - using type = T*; - constexpr type operator()(T* t) const noexcept { - return t; - } + using type = T*; + constexpr type operator()(T* t) const noexcept { + return t; + } }; - template struct ArrowHelper().operator->())>> { - using type = decltype(std::declval().operator->()); - type operator()(T& t) const { - return t.operator->(); - } + using type = decltype(std::declval().operator->()); + type operator()(T& t) const { + return t.operator->(); + } }; template using arrow = typename detail::ArrowHelper::type; - + } + + // type of C::iterator::operator->, also works with pointers + // void if the iterator has no operator-> + template + using iterator_arrow = detail::arrow>; + + template + using reverse_iterator_arrow = detail::arrow>; + + // applys the -> operator to an object, if the object is a pointer, + // it returns the pointer + template + detail::arrow apply_arrow(T& t) { + return detail::ArrowHelper{}(t); + } + + // For iterators that have an operator* which returns a value + // they can return this type from their operator-> instead, which will + // wrap an object and allow it to be used with arrow + template + class ArrowProxy { + private: + using TPlain = typename std::remove_reference::type; + T obj; + + public: + constexpr ArrowProxy(T&& in_obj) : obj(std::forward(in_obj)) {} + + TPlain* operator->() { + return &obj; } - - // type of C::iterator::operator->, also works with pointers - // void if the iterator has no operator-> - template - using iterator_arrow = detail::arrow>; - - template - using reverse_iterator_arrow = detail::arrow>; - - // applys the -> operator to an object, if the object is a pointer, - // it returns the pointer - template - detail::arrow apply_arrow(T& t) { - return detail::ArrowHelper{}(t); + }; + + template + struct is_random_access_iter : std::false_type {}; + + template + struct is_random_access_iter:: + iterator_category, + std::random_access_iterator_tag>::value, + void>::type> : std::true_type {}; + + template + using has_random_access_iter = is_random_access_iter>; + // because std::advance assumes a lot and is actually smart, I need a dumb + + // version that will work with most things + template + void dumb_advance(InputIt& iter, Distance distance = 1) { + for (Distance i(0); i < distance; ++i) { + ++iter; } + } - // For iterators that have an operator* which returns a value - // they can return this type from their operator-> instead, which will - // wrap an object and allow it to be used with arrow - template - class ArrowProxy { - private: - using TPlain = typename std::remove_reference::type; - T obj; - public: - constexpr ArrowProxy(T&& in_obj) - : obj(std::forward(in_obj)) - { } - - TPlain *operator->() { - return &obj; - } - }; - - - template - struct is_random_access_iter : std::false_type { }; - - template - struct is_random_access_iter::iterator_category, - std::random_access_iterator_tag>::value, - void>::type> : std::true_type { }; - - template - using has_random_access_iter = is_random_access_iter>; - // because std::advance assumes a lot and is actually smart, I need a dumb - - // version that will work with most things - template - void dumb_advance(InputIt& iter, Distance distance=1) { - for (Distance i(0); i < distance; ++i) { - ++iter; - } + template + void dumb_advance_impl( + Iter& iter, const Iter& end, Distance distance, std::false_type) { + for (Distance i(0); i < distance && iter != end; ++i) { + ++iter; } - - template - void dumb_advance_impl(Iter& iter, const Iter& end, - Distance distance, std::false_type) { - for (Distance i(0); i < distance && iter != end; ++i) { - ++iter; - } + } + + template + void dumb_advance_impl( + Iter& iter, const Iter& end, Distance distance, std::true_type) { + if (static_cast(end - iter) < distance) { + iter = end; + } else { + iter += distance; } - - template - void dumb_advance_impl(Iter& iter, const Iter& end, - Distance distance, std::true_type) { - if (static_cast(end - iter) < distance) { - iter = end; - } else { - iter += distance; - } + } + + // iter will not be incremented past end + template + void dumb_advance(Iter& iter, const Iter& end, Distance distance = 1) { + dumb_advance_impl(iter, end, distance, is_random_access_iter{}); + } + + template + ForwardIt dumb_next(ForwardIt it, Distance distance = 1) { + dumb_advance(it, distance); + return it; + } + + template + ForwardIt dumb_next( + ForwardIt it, const ForwardIt& end, Distance distance = 1) { + dumb_advance(it, end, distance); + return it; + } + + template + Distance dumb_size(Container&& container) { + Distance d{0}; + for (auto it = std::begin(container), end = std::end(container); it != end; + ++it) { + ++d; } - - // iter will not be incremented past end - template - void dumb_advance(Iter& iter, const Iter& end, Distance distance=1) { - dumb_advance_impl(iter, end, distance, is_random_access_iter{}); + return d; + } + + template + struct are_same : std::true_type {}; + + template + struct are_same + : std::integral_constant::value && are_same::value> {}; + + // DerefHolder holds the value gotten from an iterator dereference + // if the iterate dereferences to an lvalue references, a pointer to the + // element is stored + // if it does not, a value is stored instead + // get() returns a reference to the held item + // get_ptr() returns a pointer to the held item + // reset() replaces the currently held item + + template + class DerefHolder { + private: + 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; + + std::unique_ptr item_p; + + public: + using reference = TPlain&; + using pointer = TPlain*; + + DerefHolder() = default; + + DerefHolder(const DerefHolder& other) + : item_p{other.item_p ? new TPlain(*other.item_p) : nullptr} {} + + DerefHolder& operator=(const DerefHolder& other) { + this->item_p.reset(other.item_p ? new TPlain(*other.item_p) : nullptr); + return *this; } - template - ForwardIt dumb_next(ForwardIt it, Distance distance=1) { - dumb_advance(it, distance); - return it; - } + DerefHolder(DerefHolder&&) = default; + DerefHolder& operator=(DerefHolder&&) = default; + ~DerefHolder() = default; - template - ForwardIt dumb_next( - ForwardIt it, const ForwardIt& end, Distance distance=1) { - dumb_advance(it, end, distance); - return it; + reference get() { + return *this->item_p; } - template - Distance dumb_size(Container&& container) { - Distance d{0}; - for (auto it = std::begin(container), end = std::end(container); - it != end; - ++it) { - ++d; - } - return d; + pointer get_ptr() { + return this->item_p.get(); } + void reset(T&& item) { + item_p.reset(new TPlain(std::move(item))); + } - template - struct are_same : std::true_type { }; - - template - struct are_same - : std::integral_constant::value && are_same::value> { }; - - // DerefHolder holds the value gotten from an iterator dereference - // if the iterate dereferences to an lvalue references, a pointer to the - // element is stored - // if it does not, a value is stored instead - // get() returns a reference to the held item - // get_ptr() returns a pointer to the held item - // reset() replaces the currently held item - - template - class DerefHolder { - private: - 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; - - std::unique_ptr item_p; - - public: - using reference = TPlain&; - using pointer = TPlain*; - - DerefHolder() = default; - - DerefHolder(const DerefHolder& other) - : item_p{other.item_p ? new TPlain(*other.item_p) : nullptr} - { } - - DerefHolder& operator=(const DerefHolder& other) { - this->item_p.reset(other.item_p - ? new TPlain(*other.item_p) : nullptr); - return *this; - } - - DerefHolder(DerefHolder&&) = default; - DerefHolder& operator=(DerefHolder&&) = default; - ~DerefHolder() = default; + explicit operator bool() const { + return this->item_p; + } + }; - reference get() { - return *this->item_p; - } + // Specialization for when T is an lvalue ref. Keep this in mind + // wherever a T appears. + template + class DerefHolder::value>::type> { + public: + using reference = T; + using pointer = typename std::remove_reference::type*; - pointer get_ptr() { - return this->item_p.get(); - } + private: + pointer item_p{}; - void reset(T&& item) { - item_p.reset(new TPlain(std::move(item))); - } + public: + DerefHolder() = default; - explicit operator bool() const { - return this->item_p; - } - }; + reference get() { + return *this->item_p; + } + pointer get_ptr() { + return this->item_p; + } - // Specialization for when T is an lvalue ref. Keep this in mind - // wherever a T appears. - template - class DerefHolder::value>::type> - { - public: - using reference = T; - using pointer = typename std::remove_reference::type*; - - private: - pointer item_p{}; - - public: - DerefHolder() = default; - - reference get() { - return *this->item_p; - } - - pointer get_ptr() { - return this->item_p; - } - - void reset(T item) { - this->item_p = &item; - } - - explicit operator bool() const { - return this->item_p != nullptr; - } - }; + void reset(T item) { + this->item_p = &item; + } + explicit operator bool() const { + return this->item_p != nullptr; + } + }; } #endif diff --git a/itertools.hpp b/itertools.hpp index 1f54acff..dddbb293 100644 --- a/itertools.hpp +++ b/itertools.hpp @@ -33,5 +33,3 @@ // included explicitly #endif - - diff --git a/permutations.hpp b/permutations.hpp index 4e53f259..772c11d7 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -12,106 +12,94 @@ namespace iter { - template - class Permuter { - private: - Container container; - - using IndexVector = std::vector>; - using Permutable = IterIterWrapper; - - public: - Permuter(Container&& in_container) - : container(std::forward(in_container)) - { } - - class Iterator - : public std::iterator - { - private: - static constexpr const int COMPLETE = -1; - static bool cmp_iters( - const iterator_type& lhs, - const iterator_type& rhs) noexcept { - return *lhs < *rhs; - } - - Permutable working_set; - int steps{}; - - public: - Iterator(iterator_type&& sub_iter, - iterator_type&& sub_end) - : steps{ sub_iter != sub_end ? 0 : COMPLETE } - { - // done like this instead of using vector ctor with - // two iterators because that causes a substitution - // failure when the iterator is minimal - while (sub_iter != sub_end) { - this->working_set.get().push_back(sub_iter); - ++sub_iter; - } - std::sort(std::begin(working_set.get()), - std::end(working_set.get()), - cmp_iters); - } - - Permutable& operator*() { - return this->working_set; - } - - Permutable *operator->() { - return &this->working_set; - } - - Iterator& operator++() { - ++this->steps; - if (!std::next_permutation(std::begin(working_set.get()), - std::end(working_set.get()), cmp_iters)) { - this->steps = COMPLETE; - } - return *this; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - bool operator!=(const Iterator& other) const { - return !(*this == other); - } - - bool operator==(const Iterator& other) const { - return this->steps == other.steps; - } - }; - - Iterator begin() { - return {std::begin(this->container), - std::end(this->container)}; - } - - Iterator end() { - return {std::end(this->container), - std::end(this->container)}; - } - - + template + class Permuter { + private: + Container container; + + using IndexVector = std::vector>; + using Permutable = IterIterWrapper; + + public: + Permuter(Container&& in_container) + : container(std::forward(in_container)) {} + + class Iterator : public std::iterator { + private: + static constexpr const int COMPLETE = -1; + static bool cmp_iters(const iterator_type& lhs, + const iterator_type& rhs) noexcept { + return *lhs < *rhs; + } + + Permutable working_set; + int steps{}; + + public: + Iterator(iterator_type&& sub_iter, + iterator_type&& sub_end) + : steps{sub_iter != sub_end ? 0 : COMPLETE} { + // done like this instead of using vector ctor with + // two iterators because that causes a substitution + // failure when the iterator is minimal + while (sub_iter != sub_end) { + this->working_set.get().push_back(sub_iter); + ++sub_iter; + } + std::sort(std::begin(working_set.get()), std::end(working_set.get()), + cmp_iters); + } + + Permutable& operator*() { + return this->working_set; + } + + Permutable* operator->() { + return &this->working_set; + } + + Iterator& operator++() { + ++this->steps; + if (!std::next_permutation(std::begin(working_set.get()), + std::end(working_set.get()), cmp_iters)) { + this->steps = COMPLETE; + } + return *this; + } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + bool operator!=(const Iterator& other) const { + return !(*this == other); + } + + bool operator==(const Iterator& other) const { + return this->steps == other.steps; + } }; - template - Permuter permutations(Container&& container) { - return {std::forward(container)}; + Iterator begin() { + return {std::begin(this->container), std::end(this->container)}; } - template - Permuter> permutations( - std::initializer_list il) { - return {std::move(il)}; + Iterator end() { + return {std::end(this->container), std::end(this->container)}; } + }; + + template + Permuter permutations(Container&& container) { + return {std::forward(container)}; + } + template + Permuter> permutations(std::initializer_list il) { + return {std::move(il)}; + } } #endif diff --git a/powerset.hpp b/powerset.hpp index a87b73f2..dda2f4fe 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -12,95 +12,87 @@ #include namespace iter { - template - class Powersetter { - private: - Container container; - using CombinatorType = - decltype(combinations(std::declval(), 0)); - - public: - Powersetter(Container&& in_container) - : container(std::forward(in_container)) - { } - - class Iterator - : public std::iterator< - std::input_iterator_tag, CombinatorType> - { - private: - typename std::remove_reference::type * - container_p; - std::size_t set_size; - std::shared_ptr comb; - iterator_type comb_iter; - iterator_type comb_end; - - public: - Iterator(Container& in_container, std::size_t sz) - : container_p{&in_container}, - set_size{sz}, - comb{new CombinatorType( - combinations(in_container, sz))}, - comb_iter{std::begin(*comb)}, - comb_end{std::end(*comb)} - { } - - Iterator& operator++() { - ++this->comb_iter; - if (this->comb_iter == this->comb_end) { - ++this->set_size; - this->comb.reset(new CombinatorType(combinations( - *this->container_p, - this->set_size))); - this->comb_iter = std::begin(*this->comb); - this->comb_end = std::end(*this->comb); - } - return *this; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - iterator_deref operator*() { - return *this->comb_iter; - } - - iterator_arrow operator->() { - apply_arrow(this->comb_iter); - } - - bool operator != (const Iterator& other) const { - return !(*this == other); - } - - bool operator==(const Iterator& other) const { - return this->set_size == other.set_size - && this->comb_iter == other.comb_iter; - } - }; - - Iterator begin() { - return {this->container, 0}; - } - - Iterator end() { - return {this->container, dumb_size(this->container) + 1}; - } + template + class Powersetter { + private: + Container container; + using CombinatorType = + decltype(combinations(std::declval(), 0)); + + public: + Powersetter(Container&& in_container) + : container(std::forward(in_container)) {} + + class Iterator + : public std::iterator { + private: + typename std::remove_reference::type* container_p; + std::size_t set_size; + std::shared_ptr comb; + iterator_type comb_iter; + iterator_type comb_end; + + public: + Iterator(Container& in_container, std::size_t sz) + : container_p{&in_container}, + set_size{sz}, + comb{new CombinatorType(combinations(in_container, sz))}, + comb_iter{std::begin(*comb)}, + comb_end{std::end(*comb)} {} + + Iterator& operator++() { + ++this->comb_iter; + if (this->comb_iter == this->comb_end) { + ++this->set_size; + this->comb.reset(new CombinatorType( + combinations(*this->container_p, this->set_size))); + this->comb_iter = std::begin(*this->comb); + this->comb_end = std::end(*this->comb); + } + return *this; + } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + iterator_deref operator*() { + return *this->comb_iter; + } + + iterator_arrow operator->() { + apply_arrow(this->comb_iter); + } + + bool operator!=(const Iterator& other) const { + return !(*this == other); + } + + bool operator==(const Iterator& other) const { + return this->set_size == other.set_size + && this->comb_iter == other.comb_iter; + } }; - template - Powersetter powerset(Container&& container) { - return {std::forward(container)}; + Iterator begin() { + return {this->container, 0}; } - template - Powersetter> powerset( - std::initializer_list il) { - return {std::move(il)}; + Iterator end() { + return {this->container, dumb_size(this->container) + 1}; } + }; + + template + Powersetter powerset(Container&& container) { + return {std::forward(container)}; + } + + template + Powersetter> powerset(std::initializer_list il) { + return {std::move(il)}; + } } #endif diff --git a/product.hpp b/product.hpp index c0c90858..77f01e33 100644 --- a/product.hpp +++ b/product.hpp @@ -9,167 +9,154 @@ #include namespace iter { - template - class Productor; - - template - Productor product(Containers&&...); - - // specialization for at least 1 template argument - template - class Productor { - static_assert(!std::is_rvalue_reference::value, - "Itertools cannot be templated with rvalue references"); - - friend Productor product( - Container&&, RestContainers&&...); - - template - friend class Productor; - - using ProdIterDeref = std::tuple< - iterator_deref, iterator_deref...>; - - private: - Container container; - Productor rest_products; - Productor(Container&& in_container, RestContainers&&... rest) - : container(std::forward(in_container)), - rest_products{std::forward(rest)...} - { } - - public: - class Iterator - : public std::iterator - { - private: - using RestIter = - typename Productor::Iterator; - - iterator_type iter; - iterator_type begin; - - RestIter rest_iter; - RestIter rest_end; - public: - constexpr static const bool is_base_iter = false; - Iterator(const iterator_type& it, - RestIter&& rest, - RestIter&& in_rest_end) - : iter{it}, - begin{it}, - rest_iter{rest}, - rest_end{in_rest_end} - { } - - void reset() { - this->iter = this->begin; - } - - Iterator& operator++() { - ++this->rest_iter; - if (!(this->rest_iter != this->rest_end)) { - this->rest_iter.reset(); - ++this->iter; - } - return *this; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - bool operator!=(const Iterator& other) const { - return this->iter != other.iter && - (RestIter::is_base_iter - || this->rest_iter != other.rest_iter); - } - - bool operator==(const Iterator& other) const { - return !(*this != other); - } - - - ProdIterDeref operator*() { - return std::tuple_cat( - std::tuple>{ - *this->iter}, - *this->rest_iter); - } - - ArrowProxy operator->() { - return {**this}; - } - }; - - Iterator begin() { - return {std::begin(this->container), - std::begin(this->rest_products), - std::end(this->rest_products)}; - } - - Iterator end() { - return {std::end(this->container), - std::end(this->rest_products), - std::end(this->rest_products)}; - } + template + class Productor; + + template + Productor product(Containers&&...); + + // specialization for at least 1 template argument + template + class Productor { + static_assert(!std::is_rvalue_reference::value, + "Itertools cannot be templated with rvalue references"); + + friend Productor product( + Container&&, RestContainers&&...); + + template + friend class Productor; + + using ProdIterDeref = std::tuple, + iterator_deref...>; + + private: + Container container; + Productor rest_products; + Productor(Container&& in_container, RestContainers&&... rest) + : container(std::forward(in_container)), + rest_products{std::forward(rest)...} {} + + public: + class Iterator + : public std::iterator { + private: + using RestIter = typename Productor::Iterator; + + iterator_type iter; + iterator_type begin; + + RestIter rest_iter; + RestIter rest_end; + + public: + constexpr static const bool is_base_iter = false; + Iterator(const iterator_type& it, RestIter&& rest, + RestIter&& in_rest_end) + : iter{it}, begin{it}, rest_iter{rest}, rest_end{in_rest_end} {} + + void reset() { + this->iter = this->begin; + } + + Iterator& operator++() { + ++this->rest_iter; + if (!(this->rest_iter != this->rest_end)) { + this->rest_iter.reset(); + ++this->iter; + } + return *this; + } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + bool operator!=(const Iterator& other) const { + return this->iter != other.iter + && (RestIter::is_base_iter + || this->rest_iter != other.rest_iter); + } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } + + ProdIterDeref operator*() { + return std::tuple_cat( + std::tuple>{*this->iter}, + *this->rest_iter); + } + + ArrowProxy operator->() { + return {**this}; + } }; + Iterator begin() { + return {std::begin(this->container), std::begin(this->rest_products), + std::end(this->rest_products)}; + } - template <> - class Productor<> { - public: - class Iterator - : public std::iterator> - { - public: - constexpr static const bool is_base_iter = true; - - void reset() { } - - Iterator& operator++() { - return *this; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - // see note in zip about base case operator!= - bool operator!=(const Iterator&) const { - return false; - } - - bool operator==(const Iterator& other) const { - return !(*this != other); - } - - std::tuple<> operator*() const { - return {}; - } - }; - - Iterator begin() { - return {}; - } - - Iterator end() { - return {}; - } + Iterator end() { + return {std::end(this->container), std::end(this->rest_products), + std::end(this->rest_products)}; + } + }; + + template <> + class Productor<> { + public: + class Iterator + : public std::iterator> { + public: + constexpr static const bool is_base_iter = true; + + void reset() {} + + Iterator& operator++() { + return *this; + } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + // see note in zip about base case operator!= + bool operator!=(const Iterator&) const { + return false; + } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } + + std::tuple<> operator*() const { + return {}; + } }; - template - Productor product(Containers&&... containers) { - return {std::forward(containers)...}; + Iterator begin() { + return {}; } - constexpr std::array, 1> product() { - return {{}}; + Iterator end() { + return {}; } + }; + + template + Productor product(Containers&&... containers) { + return {std::forward(containers)...}; + } + + constexpr std::array, 1> product() { + return {{}}; + } } #endif diff --git a/range.hpp b/range.hpp index f412a93b..fb955e02 100644 --- a/range.hpp +++ b/range.hpp @@ -10,261 +10,237 @@ namespace iter { - template ::value> - class RangeIterData; - - // everything except floats - template - class RangeIterData { - private: - T value_{}; - T step_{}; - public: - constexpr RangeIterData() noexcept =default; - constexpr RangeIterData(T in_value, T in_step) noexcept - : value_{in_value}, - step_{in_step} - { } - - constexpr T value() const noexcept { - return this->value_; - } - - constexpr T step() const noexcept { - return this->step_; - } - - void inc() noexcept { - this->value_ += step_; - } - - constexpr bool operator==(const RangeIterData& other) - const noexcept { - return this->value_ == other.value_; - } - - constexpr bool operator!=(const RangeIterData& other) - const noexcept { - return !(*this == other); - } - }; + template ::value> + class RangeIterData; + + // everything except floats + template + class RangeIterData { + private: + T value_{}; + T step_{}; + + public: + constexpr RangeIterData() noexcept = default; + constexpr RangeIterData(T in_value, T in_step) noexcept : value_{in_value}, + step_{in_step} {} + + constexpr T value() const noexcept { + return this->value_; + } - // float data - template - class RangeIterData { - private: - T start_{}; - T value_{}; - T step_{}; - unsigned long steps_taken{}; - public: - constexpr RangeIterData() noexcept =default; - constexpr RangeIterData(T in_start, T in_step) noexcept - : start_{in_start}, - value_{in_start}, - step_{in_step} - { } - - constexpr T value() const noexcept { - return this->value_; - } - - constexpr T step() const noexcept { - return this->step_; - } - - void inc() noexcept { - ++this->steps_taken; - value_ = this->start_ + - (this->step_ * this->steps_taken); - } - - constexpr bool operator==(const RangeIterData& other) - const noexcept { - // if the difference between the two values is less than the - // step size, they are considered equal - return (this->value_ < other.value_ ? - other.value_ - this->value_ : - this->value_ - other.value_) < this->step_; - } - - constexpr bool operator!=(const RangeIterData& other) - const noexcept { - return !(*this == other); - } - }; + constexpr T step() const noexcept { + return this->step_; + } + void inc() noexcept { + this->value_ += step_; + } - template - class Range; - - template - constexpr Range range(T) noexcept; - template - constexpr Range range(T, T) noexcept; - template - constexpr Range range(T, T, T) noexcept; - - // General version for everything not a float - template - class Range { - friend Range range(T); - friend Range range(T, T); - friend Range range(T, T, T); - private: - const T start; - const T stop; - const T step; - - constexpr Range(T in_stop) noexcept - : start{0}, - stop{in_stop}, - step{1} - { } - - constexpr Range(T in_start, T in_stop, T in_step =1) noexcept - : start{in_start}, - stop{in_stop}, - step{in_step} - { } - - public: - // the reference type here is T, which doesn't strictly follow all - // of the rules, but std::vector::iterator::reference isn't - // a reference type either, this isn't any worse - - class Iterator - : public std::iterator< - std::forward_iterator_tag, - T, - std::ptrdiff_t, - T*, - T> - { - private: - RangeIterData data; - bool is_end; - - // compare unsigned values - static bool not_equal_to_impl( - const Iterator& iter, const Iterator& end_iter, - std::true_type ) noexcept { - assert(!iter.is_end); - assert(end_iter.is_end); - return iter.data.value() < end_iter.data.value(); - } - - // compare signed values - static bool not_equal_to_impl( - const Iterator& iter, const Iterator& end_iter, - std::false_type) noexcept { - assert(!iter.is_end); - assert(end_iter.is_end); - return !(iter.data.step() > 0 && iter.data.value() - >= end_iter.data.value()) - && !(iter.data.step() < 0 && iter.data.value() - <= end_iter.data.value()); - } - - static bool not_equal_to_end(const Iterator& lhs, - const Iterator& rhs) noexcept{ - if (rhs.is_end) { - return not_equal_to_impl( - lhs, rhs, std::is_unsigned{}); - } else { - return not_equal_to_impl( - rhs, lhs, std::is_unsigned{}); - } - } - - public: - constexpr Iterator() noexcept =default; - - constexpr Iterator(T in_value, T in_step, bool in_is_end) - noexcept - : data(in_value, in_step), - is_end{in_is_end} - { } - - constexpr T operator*() const noexcept { - return this->data.value(); - } - - constexpr ArrowProxy operator->() const noexcept { - return {**this}; - } - - Iterator& operator++() noexcept { - this->data.inc(); - return *this; - } - - Iterator operator++(int) noexcept { - auto ret = *this; - ++*this; - return ret; - } - - // This operator would more accurately read as "in bounds" - // or "incomplete" because exact comparison with the end - // isn't good enough for the purposes of this Iterator. - // There are two odd cases that need to be handled - // - // 1) The Range is infinite, such as - // Range (-1, 0, -1) which would go forever down toward - // infinitely (theoretically). If this occurs, the Range - // will instead effectively be empty - // - // 2) (stop - start) % step != 0. For - // example Range(1, 10, 2). The iterator will never be - // exactly equal to the stop value. - // - // Another way to think about it is that the "end" - // iterator represents the range of values that are invalid - // So, if an iterator is not equal to that, it is valid - // - // Two end iterators will compare equal - // - // Two non-end iterators will compare by their stored values - bool operator!=(const Iterator& other) const noexcept { - if (this->is_end && other.is_end) { - return false; - } - - if (!this->is_end && !other.is_end) { - return this->data != other.data; - } - return not_equal_to_end(*this, other); - } - - bool operator==(const Iterator& other) const noexcept { - return !(*this != other); - } - }; - - constexpr Iterator begin() const noexcept { - return {start, step, false}; - } - - constexpr Iterator end() const noexcept { - return {stop, step, true}; - } - }; + constexpr bool operator==(const RangeIterData& other) const noexcept { + return this->value_ == other.value_; + } - template - constexpr Range range(T stop) noexcept { - return {stop}; + constexpr bool operator!=(const RangeIterData& other) const noexcept { + return !(*this == other); } + }; + + // float data + template + class RangeIterData { + private: + T start_{}; + T value_{}; + T step_{}; + unsigned long steps_taken{}; + + public: + constexpr RangeIterData() noexcept = default; + constexpr RangeIterData(T in_start, T in_step) noexcept : start_{in_start}, + value_{in_start}, + step_{in_step} {} + + constexpr T value() const noexcept { + return this->value_; + } + + constexpr T step() const noexcept { + return this->step_; + } + + void inc() noexcept { + ++this->steps_taken; + value_ = this->start_ + (this->step_ * this->steps_taken); + } + + constexpr bool operator==(const RangeIterData& other) const noexcept { + // if the difference between the two values is less than the + // step size, they are considered equal + return (this->value_ < other.value_ ? other.value_ - this->value_ + : this->value_ - other.value_) + < this->step_; + } + + constexpr bool operator!=(const RangeIterData& other) const noexcept { + return !(*this == other); + } + }; + + template + class Range; + + template + constexpr Range range(T) noexcept; + template + constexpr Range range(T, T) noexcept; + template + constexpr Range range(T, T, T) noexcept; + + // General version for everything not a float + template + class Range { + friend Range range(T); + friend Range range(T, T); + friend Range range(T, T, T); + + private: + const T start; + const T stop; + const T step; + + constexpr Range(T in_stop) noexcept : start{0}, stop{in_stop}, step{1} {} + + constexpr Range(T in_start, T in_stop, T in_step = 1) noexcept + : start{in_start}, + stop{in_stop}, + step{in_step} {} + + public: + // the reference type here is T, which doesn't strictly follow all + // of the rules, but std::vector::iterator::reference isn't + // a reference type either, this isn't any worse + + class Iterator : public std::iterator { + private: + RangeIterData data; + bool is_end; + + // compare unsigned values + static bool not_equal_to_impl(const Iterator& iter, + const Iterator& end_iter, std::true_type) noexcept { + assert(!iter.is_end); + assert(end_iter.is_end); + return iter.data.value() < end_iter.data.value(); + } + + // compare signed values + static bool not_equal_to_impl(const Iterator& iter, + const Iterator& end_iter, std::false_type) noexcept { + assert(!iter.is_end); + assert(end_iter.is_end); + return !(iter.data.step() > 0 + && iter.data.value() >= end_iter.data.value()) + && !(iter.data.step() < 0 + && iter.data.value() <= end_iter.data.value()); + } + + static bool not_equal_to_end( + const Iterator& lhs, const Iterator& rhs) noexcept { + if (rhs.is_end) { + return not_equal_to_impl(lhs, rhs, std::is_unsigned{}); + } else { + return not_equal_to_impl(rhs, lhs, std::is_unsigned{}); + } + } + + public: + constexpr Iterator() noexcept = default; + + constexpr Iterator(T in_value, T in_step, bool in_is_end) noexcept + : data(in_value, in_step), + is_end{in_is_end} {} + + constexpr T operator*() const noexcept { + return this->data.value(); + } + + constexpr ArrowProxy operator->() const noexcept { + return {**this}; + } + + Iterator& operator++() noexcept { + this->data.inc(); + return *this; + } + + Iterator operator++(int) noexcept { + auto ret = *this; + ++*this; + return ret; + } + + // This operator would more accurately read as "in bounds" + // or "incomplete" because exact comparison with the end + // isn't good enough for the purposes of this Iterator. + // There are two odd cases that need to be handled + // + // 1) The Range is infinite, such as + // Range (-1, 0, -1) which would go forever down toward + // infinitely (theoretically). If this occurs, the Range + // will instead effectively be empty + // + // 2) (stop - start) % step != 0. For + // example Range(1, 10, 2). The iterator will never be + // exactly equal to the stop value. + // + // Another way to think about it is that the "end" + // iterator represents the range of values that are invalid + // So, if an iterator is not equal to that, it is valid + // + // Two end iterators will compare equal + // + // Two non-end iterators will compare by their stored values + bool operator!=(const Iterator& other) const noexcept { + if (this->is_end && other.is_end) { + return false; + } + + if (!this->is_end && !other.is_end) { + return this->data != other.data; + } + return not_equal_to_end(*this, other); + } + + bool operator==(const Iterator& other) const noexcept { + return !(*this != other); + } + }; - template - constexpr Range range(T start, T stop) noexcept { - return {start, stop}; + constexpr Iterator begin() const noexcept { + return {start, step, false}; } - template - constexpr Range range(T start, T stop, T step) noexcept { - return step == T(0) ? Range{0} : Range{start, stop, step}; + constexpr Iterator end() const noexcept { + return {stop, step, true}; } + }; + + template + constexpr Range range(T stop) noexcept { + return {stop}; + } + + template + constexpr Range range(T start, T stop) noexcept { + return {start, stop}; + } + + template + constexpr Range range(T start, T stop, T step) noexcept { + return step == T(0) ? Range{0} : Range{start, stop, step}; + } } -#endif // #ifndef ITER_RANGE_H_ +#endif // #ifndef ITER_RANGE_H_ diff --git a/repeat.hpp b/repeat.hpp index b2449baf..b2ba8ff7 100644 --- a/repeat.hpp +++ b/repeat.hpp @@ -6,148 +6,140 @@ #include namespace iter { - template - class RepeaterWithCount ; - - template - constexpr RepeaterWithCount repeat(T&&, int); - - template - class RepeaterWithCount { - friend RepeaterWithCount repeat(T&&, int); - private: - T elem; - int count; - - constexpr RepeaterWithCount(T e, int c) - : elem(std::forward(e)), - count{c} - { } - - using TPlain = typename std::remove_reference::type; - public: - class Iterator - : public std::iterator - { - private: - const TPlain *elem; - int count; - public: - constexpr Iterator(const TPlain* e, int c) - : elem{e}, - count{c} - { } - - Iterator& operator++() { - --this->count; - return *this; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - constexpr bool operator!=(const Iterator& other) const { - return !(*this == other); - } - - constexpr bool operator==(const Iterator& other) const { - return this->count == other.count; - } - - constexpr const TPlain& operator*() const { - return *this->elem; - } - - constexpr const TPlain* operator->() const { - return this->elem; - } - }; - - constexpr Iterator begin() { - return {&this->elem, this->count}; - } - - constexpr Iterator end() { - return {&this->elem, 0}; - } + template + class RepeaterWithCount; + template + constexpr RepeaterWithCount repeat(T&&, int); + + template + class RepeaterWithCount { + friend RepeaterWithCount repeat(T&&, int); + + private: + T elem; + int count; + + constexpr RepeaterWithCount(T e, int c) + : elem(std::forward(e)), count{c} {} + + using TPlain = typename std::remove_reference::type; + + public: + class Iterator + : public std::iterator { + private: + const TPlain* elem; + int count; + + public: + constexpr Iterator(const TPlain* e, int c) : elem{e}, count{c} {} + + Iterator& operator++() { + --this->count; + return *this; + } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + constexpr bool operator!=(const Iterator& other) const { + return !(*this == other); + } + + constexpr bool operator==(const Iterator& other) const { + return this->count == other.count; + } + + constexpr const TPlain& operator*() const { + return *this->elem; + } + + constexpr const TPlain* operator->() const { + return this->elem; + } }; - - template - constexpr RepeaterWithCount repeat(T&& e, int count) { - return {std::forward(e), count < 0 ? 0 : count}; + + constexpr Iterator begin() { + return {&this->elem, this->count}; + } + + constexpr Iterator end() { + return {&this->elem, 0}; } + }; + + template + constexpr RepeaterWithCount repeat(T&& e, int count) { + return {std::forward(e), count < 0 ? 0 : count}; + } - template - class Repeater; - - template - constexpr Repeater repeat(T&&); - - template - class Repeater{ - friend Repeater repeat(T&&); - private: - using TPlain = typename std::remove_reference::type; - T elem; - - constexpr Repeater(T e) - : elem(std::forward(e)) - { } - public: - class Iterator - : public std::iterator - { - private: - const TPlain *elem; - - public: - constexpr Iterator(const TPlain* e) - : elem{e} - { } - - constexpr const Iterator& operator++() const { - return *this; - } - - constexpr Iterator operator++(int) const { - return *this; - } - - constexpr bool operator!=(const Iterator&) const { - return true; - } - - constexpr bool operator==(const Iterator&) const { - return false; - } - - constexpr const TPlain& operator*() const { - return *this->elem; - } - - constexpr const TPlain* operator->() const { - return this->elem; - } - }; - - - constexpr Iterator begin() { - return {&this->elem}; - } - - constexpr Iterator end() { - return {nullptr}; - } + template + class Repeater; + + template + constexpr Repeater repeat(T&&); + + template + class Repeater { + friend Repeater repeat(T&&); + + private: + using TPlain = typename std::remove_reference::type; + T elem; + + constexpr Repeater(T e) : elem(std::forward(e)) {} + + public: + class Iterator + : public std::iterator { + private: + const TPlain* elem; + + public: + constexpr Iterator(const TPlain* e) : elem{e} {} + + constexpr const Iterator& operator++() const { + return *this; + } + + constexpr Iterator operator++(int) const { + return *this; + } + + constexpr bool operator!=(const Iterator&) const { + return true; + } + + constexpr bool operator==(const Iterator&) const { + return false; + } + + constexpr const TPlain& operator*() const { + return *this->elem; + } + + constexpr const TPlain* operator->() const { + return this->elem; + } }; - template - constexpr Repeater repeat(T&& e) { - return {std::forward(e)}; + constexpr Iterator begin() { + return {&this->elem}; } + + constexpr Iterator end() { + return {nullptr}; + } + }; + + template + constexpr Repeater repeat(T&& e) { + return {std::forward(e)}; + } } #endif diff --git a/reversed.hpp b/reversed.hpp index 795cb7ea..ccc63470 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -7,149 +7,138 @@ #include namespace iter { - template - class Reverser; - - template - Reverser reversed(Container&&); - - - template - class Reverser { - private: - Container container; - friend Reverser reversed(Container&&); - - Reverser(Container&& in_container) - : container(std::forward(in_container)) - { } - - public: - class Iterator : public std::iterator< - std::input_iterator_tag, - iterator_traits_deref> - { - private: - reverse_iterator_type sub_iter; - public: - Iterator (reverse_iterator_type&& iter) - : sub_iter{std::move(iter)} - { } - - reverse_iterator_deref operator*() { - return *this->sub_iter; - } - - reverse_iterator_arrow operator->() { - return apply_arrow(this->sub_iter); - } - - 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->container.rbegin()}; - } - - Iterator end() { - return {this->container.rend()}; - } - + template + class Reverser; + + template + Reverser reversed(Container&&); + + template + class Reverser { + private: + Container container; + friend Reverser reversed(Container&&); + + Reverser(Container&& in_container) + : container(std::forward(in_container)) {} + + public: + class Iterator : public std::iterator> { + private: + reverse_iterator_type sub_iter; + + public: + Iterator(reverse_iterator_type&& iter) + : sub_iter{std::move(iter)} {} + + reverse_iterator_deref operator*() { + return *this->sub_iter; + } + + reverse_iterator_arrow operator->() { + return apply_arrow(this->sub_iter); + } + + 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); + } }; - template - Reverser reversed(Container&& container) { - return {std::forward(container)}; + Iterator begin() { + return {this->container.rbegin()}; } - // - // 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} - { } - - T& operator*() { - return *(this->sub_iter - 1); - } - - T *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}; - } - + Iterator end() { + return {this->container.rend()}; + } + }; + + template + 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} {} + + T& operator*() { + return *(this->sub_iter - 1); + } + + T* 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); + } }; - template - Reverser reversed(T (&array)[N]) { - return {array}; + Iterator begin() { + return {this->array + N}; + } + + Iterator end() { + return {this->array}; } + }; + template + Reverser reversed(T(&array)[N]) { + return {array}; + } } #endif diff --git a/slice.hpp b/slice.hpp index 1880522d..671e3a68 100644 --- a/slice.hpp +++ b/slice.hpp @@ -7,153 +7,140 @@ #include #include - namespace iter { - template - class Slice; - - template - Slice slice( - Container&& container, - DifferenceType start, DifferenceType stop, DifferenceType step=1); - - template - Slice slice( - Container&& container, DifferenceType stop); - - template - Slice, DifferenceType> slice( - std::initializer_list il, DifferenceType start, - DifferenceType stop, DifferenceType step=1); - - template - Slice, DifferenceType> slice( - std::initializer_list il, DifferenceType stop); - - template - class Slice { - private: - Container container; - DifferenceType start; - DifferenceType stop; - DifferenceType step; - - friend Slice slice( - Container&&, DifferenceType, DifferenceType, - DifferenceType); - - friend Slice slice( - Container&&, DifferenceType); - - Slice(Container&& in_container, DifferenceType in_start, - DifferenceType in_stop, DifferenceType in_step) - : container(std::forward(in_container)), - start{in_start < in_stop && in_step > 0 ? in_start : in_stop}, - stop{in_stop}, - step{in_step} - { } - - - public: - class Iterator - : public std::iterator> - { - private: - iterator_type sub_iter; - iterator_type sub_end; - DifferenceType current; - DifferenceType stop; - DifferenceType step; - - public: - Iterator (iterator_type&& si, - iterator_type&& se, - DifferenceType in_start, - DifferenceType in_stop, - DifferenceType in_step) - : sub_iter{std::move(si)}, - sub_end{std::move(se)}, - current{in_start}, - stop{in_stop}, - step{in_step} - { } - - iterator_deref operator*() { - return *this->sub_iter; - } - - iterator_arrow operator->() { - return apply_arrow(this->sub_iter); - } - - Iterator& operator++() { - dumb_advance(this->sub_iter, this->sub_end,this->step); - this->current += this->step; - if (this->stop < this->current ) { - this->current = this->stop; - } - return *this; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter - && this->current != other.current; - } - - bool operator==(const Iterator& other) const { - return !(*this != other); - } - }; - - Iterator begin() { - auto it = std::begin(this->container); - dumb_advance(it, std::end(this->container), this->start); - return {std::move(it), std::end(this->container), - this->start, this->stop, this->step}; - } - - Iterator end() { - return {std::end(this->container), std::end(this->container), - this->stop, this->stop, this->step}; - } - + template + class Slice; + + template + Slice slice(Container&& container, + DifferenceType start, DifferenceType stop, DifferenceType step = 1); + + template + Slice slice( + Container&& container, DifferenceType stop); + + template + Slice, DifferenceType> slice( + std::initializer_list il, DifferenceType start, DifferenceType stop, + DifferenceType step = 1); + + template + Slice, DifferenceType> slice( + std::initializer_list il, DifferenceType stop); + + template + class Slice { + private: + Container container; + DifferenceType start; + DifferenceType stop; + DifferenceType step; + + friend Slice slice( + Container&&, DifferenceType, DifferenceType, DifferenceType); + + friend Slice slice(Container&&, DifferenceType); + + Slice(Container&& in_container, DifferenceType in_start, + DifferenceType in_stop, DifferenceType in_step) + : container(std::forward(in_container)), + start{in_start < in_stop && in_step > 0 ? in_start : in_stop}, + stop{in_stop}, + step{in_step} {} + + public: + class Iterator : public std::iterator> { + private: + iterator_type sub_iter; + iterator_type sub_end; + DifferenceType current; + DifferenceType stop; + DifferenceType step; + + public: + Iterator(iterator_type&& si, iterator_type&& se, + DifferenceType in_start, DifferenceType in_stop, + DifferenceType in_step) + : sub_iter{std::move(si)}, + sub_end{std::move(se)}, + current{in_start}, + stop{in_stop}, + step{in_step} {} + + iterator_deref operator*() { + return *this->sub_iter; + } + + iterator_arrow operator->() { + return apply_arrow(this->sub_iter); + } + + Iterator& operator++() { + dumb_advance(this->sub_iter, this->sub_end, this->step); + this->current += this->step; + if (this->stop < this->current) { + this->current = this->stop; + } + return *this; + } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + bool operator!=(const Iterator& other) const { + return this->sub_iter != other.sub_iter + && this->current != other.current; + } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } }; - // Helper function to instantiate a Slice - template - Slice slice( - Container&& container, - DifferenceType start, DifferenceType stop, DifferenceType step) { - return {std::forward(container), start, stop, step}; - } - - //only give the end as an arg and assume step is 1 and begin is 0 - template - Slice slice( - Container&& container, DifferenceType stop) { - return {std::forward(container), 0, stop, 1}; - } - - template - Slice, DifferenceType> slice( - std::initializer_list il, DifferenceType start, - DifferenceType stop, DifferenceType step) { - return {std::move(il), start, stop, step}; + Iterator begin() { + auto it = std::begin(this->container); + dumb_advance(it, std::end(this->container), this->start); + return {std::move(it), std::end(this->container), this->start, this->stop, + this->step}; } - template - Slice, DifferenceType> slice( - std::initializer_list il, DifferenceType stop) { - return {std::move(il), 0, stop, 1}; + Iterator end() { + return {std::end(this->container), std::end(this->container), this->stop, + this->stop, this->step}; } + }; + + // Helper function to instantiate a Slice + template + Slice slice(Container&& container, + DifferenceType start, DifferenceType stop, DifferenceType step) { + return {std::forward(container), start, stop, step}; + } + + // only give the end as an arg and assume step is 1 and begin is 0 + template + Slice slice( + Container&& container, DifferenceType stop) { + return {std::forward(container), 0, stop, 1}; + } + + template + Slice, DifferenceType> slice( + std::initializer_list il, DifferenceType start, DifferenceType stop, + DifferenceType step) { + return {std::move(il), start, stop, step}; + } + + template + Slice, DifferenceType> slice( + std::initializer_list il, DifferenceType stop) { + return {std::move(il), 0, stop, 1}; + } } #endif diff --git a/sliding_window.hpp b/sliding_window.hpp index 36ab877e..aefbca30 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -9,116 +9,106 @@ #include namespace iter { - template - class SlidingWindow; + template + class SlidingWindow; - template - SlidingWindow sliding_window(Container&&, std::size_t); + template + SlidingWindow sliding_window(Container&&, std::size_t); + + template + SlidingWindow> sliding_window( + std::initializer_list, std::size_t); + + template + class SlidingWindow { + private: + Container container; + std::size_t window_size; + + friend SlidingWindow sliding_window(Container&&, std::size_t); template - SlidingWindow> sliding_window( - std::initializer_list, std::size_t); - - template - class SlidingWindow { - private: Container container; - std::size_t window_size; - - friend SlidingWindow sliding_window( - Container&&, std::size_t); - - template - friend SlidingWindow> sliding_window( - std::initializer_list, std::size_t); - - SlidingWindow(Container&& in_container, std::size_t win_sz) - : container(std::forward(in_container)), - window_size{win_sz} - { } - - using IndexVector = std::deque>; - using DerefVec = IterIterWrapper; - public: - - class Iterator - : public std::iterator - { - private: - iterator_type sub_iter; - DerefVec window; - - public: - Iterator(iterator_type&& in_iter, - const iterator_type& in_end, - std::size_t window_sz) - : sub_iter(std::move(in_iter)) - { - std::size_t i{0}; - while (i < window_sz - && this->sub_iter != in_end) { - this->window.get().push_back(this->sub_iter); - ++i; - if (i != window_sz) ++this->sub_iter; - } - } - - bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter; - } - - bool operator==(const Iterator& other) const { - return !(*this != other); - } - - DerefVec& operator*() { - return this->window; - } - - DerefVec *operator->() { - return this->window; - } - - Iterator& operator++() { - ++this->sub_iter; - this->window.get().pop_front(); - this->window.get().push_back(this->sub_iter); - return *this; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - }; - - Iterator begin() { - return { - (this->window_size != 0 ? - std::begin(this->container) - : std::end(this->container)), - std::end(this->container), - this->window_size}; - } - - Iterator end() { - return {std::end(this->container), - std::end(this->container), - this->window_size}; - } + friend SlidingWindow> sliding_window( + std::initializer_list, std::size_t); + + SlidingWindow(Container&& in_container, std::size_t win_sz) + : container(std::forward(in_container)), + window_size{win_sz} {} + + using IndexVector = std::deque>; + using DerefVec = IterIterWrapper; + + public: + class Iterator : public std::iterator { + private: + iterator_type sub_iter; + DerefVec window; + + public: + Iterator(iterator_type&& in_iter, + const iterator_type& in_end, std::size_t window_sz) + : sub_iter(std::move(in_iter)) { + std::size_t i{0}; + while (i < window_sz && this->sub_iter != in_end) { + this->window.get().push_back(this->sub_iter); + ++i; + if (i != window_sz) ++this->sub_iter; + } + } + + bool operator!=(const Iterator& other) const { + return this->sub_iter != other.sub_iter; + } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } + + DerefVec& operator*() { + return this->window; + } + + DerefVec* operator->() { + return this->window; + } + + Iterator& operator++() { + ++this->sub_iter; + this->window.get().pop_front(); + this->window.get().push_back(this->sub_iter); + return *this; + } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } }; - template - SlidingWindow sliding_window( - Container&& container, std::size_t window_size) { - return {std::forward(container), window_size}; + Iterator begin() { + return {(this->window_size != 0 ? std::begin(this->container) + : std::end(this->container)), + std::end(this->container), this->window_size}; } - template - SlidingWindow> sliding_window( - std::initializer_list il, std::size_t window_size) { - return {std::move(il), window_size}; + Iterator end() { + return {std::end(this->container), std::end(this->container), + this->window_size}; } + }; + + template + SlidingWindow sliding_window( + Container&& container, std::size_t window_size) { + return {std::forward(container), window_size}; + } + + template + SlidingWindow> sliding_window( + std::initializer_list il, std::size_t window_size) { + return {std::move(il), window_size}; + } } #endif diff --git a/sorted.hpp b/sorted.hpp index c68171e3..318ae415 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -9,72 +9,64 @@ #include namespace iter { - template - class Sorted; - - template - Sorted sorted(Container&&, CompareFunc); - - template - class Sorted { - private: - using IterIterWrap = - IterIterWrapper>>; - using ItIt = iterator_type; - - template - friend Sorted sorted(C&&, F); - - Container container; - IterIterWrap sorted_iters; - - template - Sorted(Container&& in_container, CompareFunc compare_func) - : container(std::forward(in_container)) - { - // Fill the sorted_iters vector with an iterator to each - // element in the container - for (auto iter = std::begin(this->container); - iter != std::end(this->container); - ++iter) { - this->sorted_iters.get().push_back(iter); - } - - // sort by comparing the elements that the iterators point to - std::sort(std::begin(sorted_iters.get()), - std::end(sorted_iters.get()), - [compare_func] (const iterator_type& it1, - const iterator_type& it2) - { return compare_func(*it1, *it2); }); - } - - public: - - ItIt begin() { - return std::begin(sorted_iters); - - } - - ItIt end() { - return std::end(sorted_iters); - } - }; - - template - Sorted sorted( - Container&& container, CompareFunc compare_func) { - return {std::forward(container), compare_func}; + template + class Sorted; + + template + Sorted sorted(Container&&, CompareFunc); + + template + class Sorted { + private: + using IterIterWrap = IterIterWrapper>>; + using ItIt = iterator_type; + + template + friend Sorted sorted(C&&, F); + + Container container; + IterIterWrap sorted_iters; + + template + Sorted(Container&& in_container, CompareFunc compare_func) + : container(std::forward(in_container)) { + // Fill the sorted_iters vector with an iterator to each + // element in the container + for (auto iter = std::begin(this->container); + iter != std::end(this->container); ++iter) { + this->sorted_iters.get().push_back(iter); + } + + // sort by comparing the elements that the iterators point to + std::sort(std::begin(sorted_iters.get()), std::end(sorted_iters.get()), + [compare_func](const iterator_type& it1, + const iterator_type& it2) { + return compare_func(*it1, *it2); + }); } - template - auto sorted(Container&& container) -> - decltype(sorted(std::forward(container), - std::less>())) - { - return sorted(std::forward(container), - std::less>()); - } + public: + ItIt begin() { + return std::begin(sorted_iters); + } + ItIt end() { + return std::end(sorted_iters); + } + }; + + template + Sorted sorted(Container&& container, CompareFunc compare_func) { + return {std::forward(container), compare_func}; + } + + template + auto sorted(Container&& container) + -> decltype(sorted(std::forward(container), + std::less>())) { + return sorted(std::forward(container), + std::less>()); + } } #endif diff --git a/takewhile.hpp b/takewhile.hpp index 6d514327..4f09fae7 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -9,134 +9,120 @@ namespace iter { - //Forward declarations of TakeWhile and takewhile - template - class TakeWhile; - - template - TakeWhile takewhile(FilterFunc, Container&&); - - template - TakeWhile> takewhile( - FilterFunc, std::initializer_list); - - template - class TakeWhile { - private: - Container container; - FilterFunc filter_func; - - friend TakeWhile takewhile( - FilterFunc, Container&&); - - template - friend TakeWhile> takewhile( - FF, std::initializer_list); - - TakeWhile(FilterFunc in_filter_func, Container&& in_container) - : container(std::forward(in_container)), - filter_func(in_filter_func) - { } - - - public: - - class Iterator - : public std::iterator> - { - private: - using Holder = DerefHolder>; - iterator_type sub_iter; - iterator_type sub_end; - Holder item; - FilterFunc *filter_func; - - void inc_sub_iter() { - ++this->sub_iter; - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); - } - } - - void check_current() { - if (this->sub_iter != this->sub_end - && !(*this->filter_func)(this->item.get())) { - this->sub_iter = this->sub_end; - } - } - - public: - Iterator(iterator_type&& iter, - iterator_type&& end, - FilterFunc& in_filter_func) - : sub_iter{std::move(iter)}, - sub_end{std::move(end)}, - filter_func(&in_filter_func) - { - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); - } - this->check_current(); - } - - typename Holder::reference operator*() { - return this->item.get(); - } - - typename Holder::pointer operator->() { - return this->item.get_ptr(); - } - - Iterator& operator++() { - this->inc_sub_iter(); - this->check_current(); - 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 {std::begin(this->container), - std::end(this->container), - this->filter_func}; - } - - Iterator end() { - return {std::end(this->container), - std::end(this->container), - this->filter_func}; - } - + // Forward declarations of TakeWhile and takewhile + template + class TakeWhile; + + template + TakeWhile takewhile(FilterFunc, Container&&); + + template + TakeWhile> takewhile( + FilterFunc, std::initializer_list); + + template + class TakeWhile { + private: + Container container; + FilterFunc filter_func; + + friend TakeWhile takewhile(FilterFunc, Container&&); + + template + friend TakeWhile> takewhile( + FF, std::initializer_list); + + TakeWhile(FilterFunc in_filter_func, Container&& in_container) + : container(std::forward(in_container)), + filter_func(in_filter_func) {} + + public: + class Iterator : public std::iterator> { + private: + using Holder = DerefHolder>; + iterator_type sub_iter; + iterator_type sub_end; + Holder item; + FilterFunc* filter_func; + + void inc_sub_iter() { + ++this->sub_iter; + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); + } + } + + void check_current() { + if (this->sub_iter != this->sub_end + && !(*this->filter_func)(this->item.get())) { + this->sub_iter = this->sub_end; + } + } + + public: + Iterator(iterator_type&& iter, iterator_type&& end, + FilterFunc& in_filter_func) + : sub_iter{std::move(iter)}, + sub_end{std::move(end)}, + filter_func(&in_filter_func) { + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); + } + this->check_current(); + } + + typename Holder::reference operator*() { + return this->item.get(); + } + + typename Holder::pointer operator->() { + return this->item.get_ptr(); + } + + Iterator& operator++() { + this->inc_sub_iter(); + this->check_current(); + 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); + } }; - template - TakeWhile takewhile( - FilterFunc filter_func, Container&& container) { - return {filter_func, std::forward(container)}; + Iterator begin() { + return {std::begin(this->container), std::end(this->container), + this->filter_func}; } - template - TakeWhile> takewhile( - FilterFunc filter_func, std::initializer_list il) - { - return {filter_func, std::move(il)}; + Iterator end() { + return {std::end(this->container), std::end(this->container), + this->filter_func}; } - + }; + + template + TakeWhile takewhile( + FilterFunc filter_func, Container&& container) { + return {filter_func, std::forward(container)}; + } + + template + TakeWhile> takewhile( + FilterFunc filter_func, std::initializer_list il) { + return {filter_func, std::move(il)}; + } } #endif diff --git a/unique_everseen.hpp b/unique_everseen.hpp index ec95eb34..b971ca62 100644 --- a/unique_everseen.hpp +++ b/unique_everseen.hpp @@ -10,48 +10,43 @@ #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 - template - auto unique_everseen(Container&& container) - -> Filter)>,Container> - { - using elem_t = iterator_deref; - std::unordered_set::type> elem_seen; +namespace iter { + // the container type must be usable in an unordered_map to achieve constant + // performance checking if it has ever been seen + 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; - } - }; - return filter(func, std::forward(container)); - } + 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; + } + }; + 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; - } - }; - return filter(func, il); - } + 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; + } + }; + return filter(func, il); + } } #endif diff --git a/unique_justseen.hpp b/unique_justseen.hpp index 3eb39cc2..442e658e 100644 --- a/unique_justseen.hpp +++ b/unique_justseen.hpp @@ -10,38 +10,35 @@ #include #include -namespace iter -{ - template - struct GroupFrontGetter{ - auto operator()(iterator_deref gb) -> - decltype(*std::begin(gb.second)) { - return *std::begin(gb.second); - } - }; - +namespace iter { + template + struct GroupFrontGetter { + 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 + auto unique_justseen(Container&& container) -> decltype(imap( + GroupFrontGetter(container)))>{}, + groupby(std::forward(container)))) { + return imap(GroupFrontGetter(container)))>{}, - groupby(std::forward(container))); - } + groupby(std::forward(container))); + } - template - auto unique_justseen(std::initializer_list il) -> - decltype(imap(GroupFrontGetter>(il)))>{}, - groupby(std::forward>(il)))) { - return imap(GroupFrontGetter + auto unique_justseen(std::initializer_list il) + -> decltype(imap(GroupFrontGetter>(il)))>{}, + groupby(std::forward>(il)))) { + return imap(GroupFrontGetter>(il)))>{}, - groupby(std::forward>(il))); - } + groupby(std::forward>(il))); + } } #endif diff --git a/zip.hpp b/zip.hpp index d8cf5457..f1cb9ae6 100644 --- a/zip.hpp +++ b/zip.hpp @@ -7,156 +7,141 @@ #include #include - namespace iter { - template - class Zipped; - - template - Zipped zip(Containers&&...); - - // specialization for at least 1 template argument - template - class Zipped { - using ZipIterDeref = - std::tuple, - iterator_deref...>; - - friend Zipped zip( - Container&&, RestContainers&&...); - - template - friend class Zipped; - - private: - Container container; - Zipped rest_zipped; - Zipped(Container&& in_container, RestContainers&&... rest) - : container(std::forward(in_container)), - rest_zipped{std::forward(rest)...} - { } - - public: - class Iterator : - public std::iterator - { - private: - using RestIter = - typename Zipped::Iterator; - - iterator_type iter; - RestIter rest_iter; - public: - constexpr static const bool is_base_iter = false; - Iterator(iterator_type&& it, RestIter&& rest) - : iter{std::move(it)}, - rest_iter{std::move(rest)} - { } - - Iterator& operator++() { - ++this->iter; - ++this->rest_iter; - return *this; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - bool operator!=(const Iterator& other) const { - return this->iter != other.iter && - (RestIter::is_base_iter || - this->rest_iter != other.rest_iter); - } - - bool operator==(const Iterator& other) const { - return !(*this != other); - } - - 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->() -> ArrowProxy { - return {**this}; - } - - }; - - Iterator begin() { - return {std::begin(this->container), - std::begin(this->rest_zipped)}; - } - - Iterator end() { - return {std::end(this->container), - std::end(this->rest_zipped)}; - } + template + class Zipped; + + template + Zipped zip(Containers&&...); + + // specialization for at least 1 template argument + template + class Zipped { + using ZipIterDeref = std::tuple, + iterator_deref...>; + + friend Zipped zip( + Container&&, RestContainers&&...); + + template + friend class Zipped; + + private: + Container container; + Zipped rest_zipped; + Zipped(Container&& in_container, RestContainers&&... rest) + : container(std::forward(in_container)), + rest_zipped{std::forward(rest)...} {} + + public: + class Iterator + : public std::iterator { + private: + using RestIter = typename Zipped::Iterator; + + iterator_type iter; + RestIter rest_iter; + + public: + constexpr static const bool is_base_iter = false; + Iterator(iterator_type&& it, RestIter&& rest) + : iter{std::move(it)}, rest_iter{std::move(rest)} {} + + Iterator& operator++() { + ++this->iter; + ++this->rest_iter; + return *this; + } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + bool operator!=(const Iterator& other) const { + return this->iter != other.iter + && (RestIter::is_base_iter + || this->rest_iter != other.rest_iter); + } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } + + 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-> () -> ArrowProxy { + return {**this}; + } }; + Iterator begin() { + return {std::begin(this->container), std::begin(this->rest_zipped)}; + } - template <> - class Zipped<> { - public: - class Iterator - : public std::iterator> - { - public: - constexpr static const bool is_base_iter = true; - - Iterator& operator++() { - return *this; - } - - Iterator operator++(int) { - 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; - } - - bool operator==(const Iterator& other) const { - return !(*this != other); - } - - std::tuple<> operator*() { - return std::tuple<>{}; - } - - auto operator->() -> ArrowProxy { - return {**this}; - } - }; - - Iterator begin() { - return {}; - } - - Iterator end() { - return {}; - } + Iterator end() { + return {std::end(this->container), std::end(this->rest_zipped)}; + } + }; + + template <> + class Zipped<> { + public: + class Iterator + : public std::iterator> { + public: + constexpr static const bool is_base_iter = true; + + Iterator& operator++() { + return *this; + } + + Iterator operator++(int) { + 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; + } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } + + std::tuple<> operator*() { + return std::tuple<>{}; + } + + auto operator-> () -> ArrowProxy { + return {**this}; + } }; - template - Zipped zip(Containers&&... containers) { - return {std::forward(containers)...}; + Iterator begin() { + return {}; } + + Iterator end() { + return {}; + } + }; + + template + Zipped zip(Containers&&... containers) { + return {std::forward(containers)...}; + } } #endif diff --git a/zip_longest.hpp b/zip_longest.hpp index 937602df..b7bff0ae 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -8,163 +8,146 @@ #include #include - namespace iter { - template - using OptIterDeref = boost::optional>; - - template - class ZippedLongest; - - template - ZippedLongest zip_longest(Containers&&...); - - template - class ZippedLongest { - static_assert(!std::is_rvalue_reference::value, - "Itertools cannot be templated with rvalue references"); - - friend ZippedLongest zip_longest( - Container&&, RestContainers&&...); - - template - friend class ZippedLongest; - - private: - using OptType = OptIterDeref; - using ZipIterDeref = - std::tuple...>; - - Container container; - ZippedLongest rest_zipped; - ZippedLongest(Container&& in_container, RestContainers&&... rest) - : container(std::forward(in_container)), - rest_zipped{std::forward(rest)...} - { } - - public: - class Iterator - : public std::iterator - { - private: - using RestIter = - typename ZippedLongest::Iterator; - - iterator_type iter; - iterator_type end; - RestIter rest_iter; - - public: - Iterator( - iterator_type&& it, - iterator_type&& in_end, - RestIter&& rest) - : iter{std::move(it)}, - end{std::move(in_end)}, - rest_iter{std::move(rest)} - { } - - Iterator& operator++() { - if (this->iter != this->end) { - ++this->iter; - } - ++this->rest_iter; - return *this; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - bool operator!=(const Iterator& other) const { - return this->iter != other.iter || - this->rest_iter != other.rest_iter; - } - - bool operator==(const Iterator& other) const { - return !(*this != other); - } - - 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); - } - } - - ArrowProxy operator->() { - return {**this}; - } - - }; - - Iterator begin() { - return {std::begin(this->container), - std::end(this->container), - std::begin(this->rest_zipped)}; - } - - Iterator end() { - return {std::end(this->container), - std::end(this->container), - std::end(this->rest_zipped)}; - } + template + using OptIterDeref = boost::optional>; + + template + class ZippedLongest; + + template + ZippedLongest zip_longest(Containers&&...); + + template + class ZippedLongest { + static_assert(!std::is_rvalue_reference::value, + "Itertools cannot be templated with rvalue references"); + + friend ZippedLongest zip_longest( + Container&&, RestContainers&&...); + + template + friend class ZippedLongest; + + private: + using OptType = OptIterDeref; + using ZipIterDeref = std::tuple...>; + + Container container; + ZippedLongest rest_zipped; + ZippedLongest(Container&& in_container, RestContainers&&... rest) + : container(std::forward(in_container)), + rest_zipped{std::forward(rest)...} {} + + public: + class Iterator + : public std::iterator { + private: + using RestIter = typename ZippedLongest::Iterator; + + iterator_type iter; + iterator_type end; + RestIter rest_iter; + + public: + Iterator(iterator_type&& it, iterator_type&& in_end, + RestIter&& rest) + : iter{std::move(it)}, + end{std::move(in_end)}, + rest_iter{std::move(rest)} {} + + Iterator& operator++() { + if (this->iter != this->end) { + ++this->iter; + } + ++this->rest_iter; + return *this; + } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + bool operator!=(const Iterator& other) const { + return this->iter != other.iter || this->rest_iter != other.rest_iter; + } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } + + 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); + } + } + + ArrowProxy operator->() { + return {**this}; + } }; + Iterator begin() { + return {std::begin(this->container), std::end(this->container), + std::begin(this->rest_zipped)}; + } - template <> - class ZippedLongest<> { - public: - class Iterator - : public std::iterator> - { - public: - Iterator& operator++() { - return *this; - } - - constexpr Iterator operator++(int) const { - return *this; - } - - constexpr bool operator!=(const Iterator&) const { - return false; - } - - constexpr bool operator==(const Iterator&) const { - return true; - } - - constexpr std::tuple<> operator*() const { - return {}; - } - - constexpr ArrowProxy> operator->() const { - return {{}}; - } - }; - - constexpr Iterator begin() const { - return {}; - } - - constexpr Iterator end() const { - return {}; - } + Iterator end() { + return {std::end(this->container), std::end(this->container), + std::end(this->rest_zipped)}; + } + }; + + template <> + class ZippedLongest<> { + public: + class Iterator + : public std::iterator> { + public: + Iterator& operator++() { + return *this; + } + + constexpr Iterator operator++(int) const { + return *this; + } + + constexpr bool operator!=(const Iterator&) const { + return false; + } + + constexpr bool operator==(const Iterator&) const { + return true; + } + + constexpr std::tuple<> operator*() const { + return {}; + } + + constexpr ArrowProxy> operator->() const { + return {{}}; + } }; - template - ZippedLongest zip_longest(Containers&&... containers) { - return {std::forward(containers)...}; + constexpr Iterator begin() const { + return {}; } + + constexpr Iterator end() const { + return {}; + } + }; + + template + ZippedLongest zip_longest(Containers&&... containers) { + return {std::forward(containers)...}; + } } #endif From 9de886f172487993bd620ccbfa4e11a03ace7353 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Wed, 19 Aug 2015 21:59:13 -0700 Subject: [PATCH 1221/1866] omits unused template parameter names --- zip.hpp | 2 +- zip_longest.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/zip.hpp b/zip.hpp index f1cb9ae6..038808df 100644 --- a/zip.hpp +++ b/zip.hpp @@ -23,7 +23,7 @@ namespace iter { friend Zipped zip( Container&&, RestContainers&&...); - template + template friend class Zipped; private: diff --git a/zip_longest.hpp b/zip_longest.hpp index b7bff0ae..7029bb50 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -27,7 +27,7 @@ namespace iter { friend ZippedLongest zip_longest( Container&&, RestContainers&&...); - template + template friend class ZippedLongest; private: From c1bdd4b088a761dcc127f3c90289a1fb578ae624 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 19 Aug 2015 23:33:10 -0700 Subject: [PATCH 1222/1866] moves Accumulator into impl{ } --- accumulate.hpp | 199 +++++++++++++++++++++++++------------------------ 1 file changed, 100 insertions(+), 99 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index 672212f6..c91319e8 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -11,126 +11,133 @@ #include namespace iter { - - // Forward declarations of Accumulator and accumulate - template - class Accumulator; + namespace impl { + template + class Accumulator; + } template - Accumulator accumulate( + impl::Accumulator accumulate( Container&&, AccumulateFunc); template - Accumulator, AccumulateFunc> accumulate( + impl::Accumulator, AccumulateFunc> accumulate( std::initializer_list, AccumulateFunc); +} - template - class Accumulator { - private: - Container container; - AccumulateFunc accumulate_func; +template +class iter::impl::Accumulator { + private: + Container container; + AccumulateFunc accumulate_func; - friend Accumulator accumulate( - Container&&, AccumulateFunc); + friend Accumulator iter::accumulate( + Container&&, AccumulateFunc); - template - friend Accumulator, AF> accumulate( - std::initializer_list, AF); + template + friend Accumulator, AF> iter::accumulate( + std::initializer_list, AF); - // AccumVal must be default constructible - using AccumVal = - typename std::remove_reference, iterator_deref)>::type>::type; + // AccumVal must be default constructible + using AccumVal = + typename std::remove_reference, iterator_deref)>::type>::type; - Accumulator(Container&& in_container, AccumulateFunc in_accumulate_func) - : container(std::forward(in_container)), - accumulate_func(in_accumulate_func) {} + Accumulator(Container&& in_container, AccumulateFunc in_accumulate_func) + : container(std::forward(in_container)), + accumulate_func(in_accumulate_func) {} - public: - class Iterator : public std::iterator { - private: - iterator_type sub_iter; - iterator_type sub_end; - AccumulateFunc* accumulate_func; - std::unique_ptr acc_val; - - public: - Iterator(iterator_type&& iter, iterator_type&& end, - AccumulateFunc in_accumulate_func) - : sub_iter{std::move(iter)}, - sub_end{std::move(end)}, - accumulate_func(&in_accumulate_func), - // only get first value if not an end iterator - acc_val{!(iter != end) ? nullptr : new AccumVal(*iter)} {} - - Iterator(const Iterator& other) - : sub_iter{other.sub_iter}, - sub_end{other.sub_end}, - accumulate_func{other.accumulate_func}, - acc_val{other.acc_val ? new AccumVal(*other.acc_val) : nullptr} {} - - Iterator& operator=(const Iterator& other) { - if (this == &other) return *this; - this->sub_iter = other.sub_iter; - this->sub_end = other.sub_end; - this->accumulate_func = other.accumulate_func; - this->acc_val.reset( - other.acc_val ? new AccumVal(*other.acc_val) : nullptr); - return *this; - } - - Iterator(Iterator&&) = default; - Iterator& operator=(Iterator&&) = default; + public: + class Iterator : public std::iterator { + private: + iterator_type sub_iter; + iterator_type sub_end; + AccumulateFunc* accumulate_func; + std::unique_ptr acc_val; - const AccumVal& operator*() const { - return *this->acc_val; - } + public: + Iterator(iterator_type&& iter, iterator_type&& end, + AccumulateFunc in_accumulate_func) + : sub_iter{std::move(iter)}, + sub_end{std::move(end)}, + accumulate_func(&in_accumulate_func), + // only get first value if not an end iterator + acc_val{!(iter != end) ? nullptr : new AccumVal(*iter)} {} + + Iterator(const Iterator& other) + : sub_iter{other.sub_iter}, + sub_end{other.sub_end}, + accumulate_func{other.accumulate_func}, + acc_val{other.acc_val ? new AccumVal(*other.acc_val) : nullptr} {} + + Iterator& operator=(const Iterator& other) { + if (this == &other) return *this; + this->sub_iter = other.sub_iter; + this->sub_end = other.sub_end; + this->accumulate_func = other.accumulate_func; + this->acc_val.reset( + other.acc_val ? new AccumVal(*other.acc_val) : nullptr); + return *this; + } - const AccumVal* operator->() const { - return this->acc_val.get(); - } + Iterator(Iterator&&) = default; + Iterator& operator=(Iterator&&) = default; - Iterator& operator++() { - ++this->sub_iter; - if (this->sub_iter != this->sub_end) { - *this->acc_val = (*accumulate_func)(*this->acc_val, *this->sub_iter); - } - return *this; - } + const AccumVal& operator*() const { + return *this->acc_val; + } - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } + const AccumVal* operator->() const { + return this->acc_val.get(); + } - bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter; + Iterator& operator++() { + ++this->sub_iter; + if (this->sub_iter != this->sub_end) { + *this->acc_val = (*accumulate_func)(*this->acc_val, *this->sub_iter); } + return *this; + } - bool operator==(const Iterator& other) const { - return !(*this != other); - } - }; + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } - Iterator begin() { - return {std::begin(this->container), std::end(this->container), - this->accumulate_func}; + bool operator!=(const Iterator& other) const { + return this->sub_iter != other.sub_iter; } - Iterator end() { - return {std::end(this->container), std::end(this->container), - this->accumulate_func}; + bool operator==(const Iterator& other) const { + return !(*this != other); } }; - // Helper function to instantiate an Accumulator - template - Accumulator accumulate( - Container&& container, AccumulateFunc accumulate_func) { - return {std::forward(container), accumulate_func}; + Iterator begin() { + return {std::begin(this->container), std::end(this->container), + this->accumulate_func}; + } + + Iterator end() { + return {std::end(this->container), std::end(this->container), + this->accumulate_func}; } +}; +template +iter::impl::Accumulator iter::accumulate( + Container&& container, AccumulateFunc accumulate_func) { + return {std::forward(container), accumulate_func}; +} + +template +iter::impl::Accumulator, AccumulateFunc> +iter::accumulate(std::initializer_list il, AccumulateFunc accumulate_func) { + return {std::move(il), accumulate_func}; +} + +namespace iter { template auto accumulate(Container&& container) -> decltype(accumulate( std::forward(container), @@ -142,12 +149,6 @@ namespace iter { typename std::remove_reference>::type>{}); } - template - Accumulator, AccumulateFunc> accumulate( - std::initializer_list il, AccumulateFunc accumulate_func) { - return {std::move(il), accumulate_func}; - } - template auto accumulate(std::initializer_list il) -> decltype(accumulate(std::move(il), std::plus{})) { From b27c6ff408de3246b9610542a696470eb8e892e5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 19 Aug 2015 23:33:31 -0700 Subject: [PATCH 1223/1866] moves Enumerable into impl { } --- enumerate.hpp | 162 +++++++++++++++++++++++++------------------------- 1 file changed, 82 insertions(+), 80 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index c43996f7..f8cbc37e 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -10,105 +10,107 @@ #include namespace iter { + namespace impl { + template + class Enumerable; + } - // Forward declarations of Enumerable and enumerate template - class Enumerable; + impl::Enumerable enumerate(Container&&); - template - Enumerable enumerate(Container&&); + template + impl::Enumerable> enumerate( + std::initializer_list); +} + +template +class iter::impl::Enumerable { + private: + Container container; + // The only thing allowed to directly instantiate an Enumerable is + // the enumerate function + friend Enumerable iter::enumerate(Container&&); template - Enumerable> enumerate(std::initializer_list); + friend Enumerable> iter::enumerate( + std::initializer_list); - template - class Enumerable { - private: - Container container; + // for IterYield + using BasePair = std::pair>; - // The only thing allowed to directly instantiate an Enumerable is - // the enumerate function - friend Enumerable enumerate(Container&&); - template - friend Enumerable> enumerate( - std::initializer_list); + // Value constructor for use only in the enumerate function + Enumerable(Container&& in_container) + : container(std::forward(in_container)) {} - // for IterYield - using BasePair = std::pair>; + public: + // "yielded" by the Enumerable::Iterator. Has a .index, and a + // .element referencing the value yielded by the subiterator + class IterYield : public BasePair { + public: + using BasePair::BasePair; + typename BasePair::first_type& index = BasePair::first; + typename BasePair::second_type& element = BasePair::second; + }; - // Value constructor for use only in the enumerate function - Enumerable(Container&& in_container) - : container(std::forward(in_container)) {} + // Holds an iterator of the contained type and a size_t for the + // index. Each call to ++ increments both of these data members. + // Each dereference returns an IterYield. + class Iterator : public std::iterator { + private: + iterator_type sub_iter; + std::size_t index; public: - // "yielded" by the Enumerable::Iterator. Has a .index, and a - // .element referencing the value yielded by the subiterator - class IterYield : public BasePair { - public: - using BasePair::BasePair; - typename BasePair::first_type& index = BasePair::first; - typename BasePair::second_type& element = BasePair::second; - }; - - // Holds an iterator of the contained type and a size_t for the - // index. Each call to ++ increments both of these data members. - // Each dereference returns an IterYield. - class Iterator : public std::iterator { - private: - iterator_type sub_iter; - std::size_t index; - - public: - Iterator(iterator_type&& si) - : sub_iter{std::move(si)}, index{0} {} - - IterYield operator*() { - return {this->index, *this->sub_iter}; - } - - ArrowProxy operator->() { - return {**this}; - } - - Iterator& operator++() { - ++this->sub_iter; - ++this->index; - 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 {std::begin(this->container)}; + Iterator(iterator_type&& si) + : sub_iter{std::move(si)}, index{0} {} + + IterYield operator*() { + return {this->index, *this->sub_iter}; + } + + ArrowProxy operator->() { + return {**this}; + } + + Iterator& operator++() { + ++this->sub_iter; + ++this->index; + return *this; + } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + bool operator!=(const Iterator& other) const { + return this->sub_iter != other.sub_iter; } - Iterator end() { - return {std::end(this->container)}; + bool operator==(const Iterator& other) const { + return !(*this != other); } }; - template - Enumerable enumerate(Container&& container) { - return {std::forward(container)}; + Iterator begin() { + return {std::begin(this->container)}; } - template - Enumerable> enumerate(std::initializer_list il) { - return {std::move(il)}; + Iterator end() { + return {std::end(this->container)}; } +}; + +template +iter::impl::Enumerable iter::enumerate(Container&& container) { + return {std::forward(container)}; +} + +template +iter::impl::Enumerable> iter::enumerate( + std::initializer_list il) { + return {std::move(il)}; } #endif From f48d5dd834a91bacd8908977b5fd770d025a0a85 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 09:17:55 -0700 Subject: [PATCH 1224/1866] moves all chain details into impl { } Chained, Chained, ChainedFromIterable, and ChainMaker --- chain.hpp | 484 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 247 insertions(+), 237 deletions(-) diff --git a/chain.hpp b/chain.hpp index c2a7db9a..7c5308ea 100644 --- a/chain.hpp +++ b/chain.hpp @@ -10,293 +10,303 @@ #include namespace iter { - // rather than a chain function, use a callable object to support - // from_iterable - class ChainMaker; - - template - class Chained { - static_assert(are_same, - iterator_deref...>::value, - "All chained iterables must have iterators that " - "dereference to the same type, including cv-qualifiers " - "and references."); - - friend class ChainMaker; - template - friend class Chained; + namespace impl { + template + class Chained; + template + class Chained; + + template + class ChainedFromIterable; + + // rather than a chain function, use a callable object to support + // .from_iterable() + class ChainMaker; + } + + extern const impl::ChainMaker chain; +} + +template +class iter::impl::Chained { + static_assert(are_same, + iterator_deref...>::value, + "All chained iterables must have iterators that " + "dereference to the same type, including cv-qualifiers " + "and references."); + + friend class ChainMaker; + template + friend class Chained; + + private: + Container container; + Chained rest_chained; + Chained(Container&& in_container, RestContainers&&... rest) + : container(std::forward(in_container)), + rest_chained{std::forward(rest)...} {} + + public: + class Iterator : public std::iterator> { private: - Container container; - Chained rest_chained; - Chained(Container&& in_container, RestContainers&&... rest) - : container(std::forward(in_container)), - rest_chained{std::forward(rest)...} {} + using RestIter = typename Chained::Iterator; + iterator_type sub_iter; + iterator_type sub_end; + RestIter rest_iter; + bool at_end; public: - class Iterator : public std::iterator> { - private: - using RestIter = typename Chained::Iterator; - iterator_type sub_iter; - iterator_type sub_end; - RestIter rest_iter; - bool at_end; - - public: - Iterator(iterator_type&& s_begin, - iterator_type&& s_end, RestIter&& in_rest_iter) - : sub_iter{std::move(s_begin)}, - sub_end{std::move(s_end)}, - rest_iter{std::move(in_rest_iter)}, - at_end{!(sub_iter != sub_end)} {} - - Iterator& operator++() { - if (this->at_end) { - ++this->rest_iter; - } else { - ++this->sub_iter; - if (!(this->sub_iter != this->sub_end)) { - this->at_end = true; - } + Iterator(iterator_type&& s_begin, + iterator_type&& s_end, RestIter&& in_rest_iter) + : sub_iter{std::move(s_begin)}, + sub_end{std::move(s_end)}, + rest_iter{std::move(in_rest_iter)}, + at_end{!(sub_iter != sub_end)} {} + + 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; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter - || this->rest_iter != other.rest_iter; } + return *this; + } - bool operator==(const Iterator& other) const { - return !(*this != other); - } + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } - iterator_deref operator*() { - return this->at_end ? *this->rest_iter : *this->sub_iter; - } + bool operator!=(const Iterator& other) const { + return this->sub_iter != other.sub_iter + || this->rest_iter != other.rest_iter; + } - iterator_arrow operator->() { - return this->at_end ? apply_arrow(this->rest_iter) - : apply_arrow(this->sub_iter); - } - }; + bool operator==(const Iterator& other) const { + return !(*this != other); + } - Iterator begin() { - return {std::begin(this->container), std::end(this->container), - std::begin(this->rest_chained)}; + iterator_deref operator*() { + return this->at_end ? *this->rest_iter : *this->sub_iter; } - Iterator end() { - return {std::end(this->container), std::end(this->container), - std::end(this->rest_chained)}; + iterator_arrow operator->() { + return this->at_end ? apply_arrow(this->rest_iter) + : apply_arrow(this->sub_iter); } }; - template - class Chained { - friend class ChainMaker; - template - friend class Chained; + Iterator begin() { + return {std::begin(this->container), std::end(this->container), + std::begin(this->rest_chained)}; + } + + Iterator end() { + return {std::end(this->container), std::end(this->container), + std::end(this->rest_chained)}; + } +}; +template +class iter::impl::Chained { + friend class ChainMaker; + template + friend class Chained; + + private: + Container container; + Chained(Container&& in_container) + : container(std::forward(in_container)) {} + + public: + class Iterator : public std::iterator> { private: - Container container; - Chained(Container&& in_container) - : container(std::forward(in_container)) {} + iterator_type sub_iter; + iterator_type sub_end; public: - class Iterator : public std::iterator> { - private: - iterator_type sub_iter; - iterator_type sub_end; - - public: - Iterator(const iterator_type& s_begin, - const iterator_type& s_end) - : sub_iter{s_begin}, sub_end{s_end} {} - - Iterator& operator++() { - ++this->sub_iter; - return *this; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } + Iterator(const iterator_type& s_begin, + const iterator_type& s_end) + : sub_iter{s_begin}, sub_end{s_end} {} - bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter; - } + Iterator& operator++() { + ++this->sub_iter; + return *this; + } - bool operator==(const Iterator& other) const { - return !(*this != other); - } + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } - iterator_deref operator*() { - return *this->sub_iter; - } + bool operator!=(const Iterator& other) const { + return this->sub_iter != other.sub_iter; + } - iterator_arrow operator->() { - return apply_arrow(this->sub_iter); - } - }; + bool operator==(const Iterator& other) const { + return !(*this != other); + } - Iterator begin() { - return {std::begin(this->container), std::end(this->container)}; + iterator_deref operator*() { + return *this->sub_iter; } - Iterator end() { - return {std::end(this->container), std::end(this->container)}; + iterator_arrow operator->() { + return apply_arrow(this->sub_iter); } }; - template - class ChainedFromIterable { + Iterator begin() { + return {std::begin(this->container), std::end(this->container)}; + } + + Iterator end() { + return {std::end(this->container), std::end(this->container)}; + } +}; + +template +class iter::impl::ChainedFromIterable { + private: + Container container; + friend class ChainMaker; + ChainedFromIterable(Container&& in_container) + : container(std::forward(in_container)) {} + + public: + class Iterator : public std::iterator>> { private: - Container container; - friend class ChainMaker; - ChainedFromIterable(Container&& in_container) - : container(std::forward(in_container)) {} + using SubContainer = iterator_deref; + using SubIter = iterator_type; - public: - class Iterator : public std::iterator>> { - private: - using SubContainer = iterator_deref; - using SubIter = iterator_type; - - iterator_type top_level_iter; - iterator_type top_level_end; - std::unique_ptr sub_iter_p; - std::unique_ptr sub_end_p; - - static std::unique_ptr clone_sub_pointer( - const SubIter* sub_iter) { - return std::unique_ptr{ - sub_iter ? new SubIter{*sub_iter} : nullptr}; - } + iterator_type top_level_iter; + iterator_type top_level_end; + std::unique_ptr sub_iter_p; + std::unique_ptr sub_end_p; - bool sub_iters_differ(const Iterator& other) const { - if (this->sub_iter_p == other.sub_iter_p) { - return false; - } - if (this->sub_iter_p == nullptr || other.sub_iter_p == nullptr) { - // since the first check tests if they're the same, - // this will return if only one is nullptr - return true; - } - return *this->sub_iter_p != *other.sub_iter_p; - } + static std::unique_ptr clone_sub_pointer(const SubIter* sub_iter) { + return std::unique_ptr{ + sub_iter ? new SubIter{*sub_iter} : nullptr}; + } - public: - Iterator(iterator_type&& top_iter, - iterator_type&& top_end) - : top_level_iter{std::move(top_iter)}, - top_level_end{std::move(top_end)}, - sub_iter_p{!(top_iter != top_end) - ? // iter == end ? - nullptr - : new SubIter{std::begin(*top_iter)}}, - sub_end_p{!(top_iter != top_end) - ? // iter == end ? - nullptr - : new SubIter{std::end(*top_iter)}} {} - - Iterator(const Iterator& other) - : top_level_iter{other.top_level_iter}, - top_level_end{other.top_level_end}, - sub_iter_p{clone_sub_pointer(other.sub_iter_p.get())}, - sub_end_p{clone_sub_pointer(other.sub_end_p.get())} {} - - Iterator& operator=(const Iterator& other) { - if (this == &other) return *this; - - this->top_level_iter = other.top_level_iter; - this->top_level_end = other.top_level_end; - this->sub_iter_p = clone_sub_pointer(other.sub_iter_p.get()); - this->sub_end_p = clone_sub_pointer(other.sub_end_p.get()); - - return *this; + bool sub_iters_differ(const Iterator& other) const { + if (this->sub_iter_p == other.sub_iter_p) { + return false; } - - Iterator(Iterator&&) = default; - Iterator& operator=(Iterator&&) = default; - ~Iterator() = default; - - Iterator& operator++() { - ++*this->sub_iter_p; - if (!(*this->sub_iter_p != *this->sub_end_p)) { - ++this->top_level_iter; - if (this->top_level_iter != this->top_level_end) { - sub_iter_p.reset(new SubIter{std::begin(*this->top_level_iter)}); - sub_end_p.reset(new SubIter{std::end(*this->top_level_iter)}); - } else { - sub_iter_p.reset(nullptr); - sub_end_p.reset(nullptr); - } - } - return *this; + if (this->sub_iter_p == nullptr || other.sub_iter_p == nullptr) { + // since the first check tests if they're the same, + // this will return if only one is nullptr + return true; } + return *this->sub_iter_p != *other.sub_iter_p; + } - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } + public: + Iterator( + iterator_type&& top_iter, iterator_type&& top_end) + : top_level_iter{std::move(top_iter)}, + top_level_end{std::move(top_end)}, + sub_iter_p{!(top_iter != top_end) + ? // iter == end ? + nullptr + : new SubIter{std::begin(*top_iter)}}, + sub_end_p{!(top_iter != top_end) ? // iter == end ? + nullptr + : new SubIter{std::end(*top_iter)}} { + } - bool operator!=(const Iterator& other) const { - return this->top_level_iter != other.top_level_iter - || this->sub_iters_differ(other); - } + Iterator(const Iterator& other) + : top_level_iter{other.top_level_iter}, + top_level_end{other.top_level_end}, + sub_iter_p{clone_sub_pointer(other.sub_iter_p.get())}, + sub_end_p{clone_sub_pointer(other.sub_end_p.get())} {} - bool operator==(const Iterator& other) const { - return !(*this != other); - } + Iterator& operator=(const Iterator& other) { + if (this == &other) return *this; - iterator_deref> operator*() { - return **this->sub_iter_p; - } + this->top_level_iter = other.top_level_iter; + this->top_level_end = other.top_level_end; + this->sub_iter_p = clone_sub_pointer(other.sub_iter_p.get()); + this->sub_end_p = clone_sub_pointer(other.sub_end_p.get()); - iterator_arrow> operator->() { - return apply_arrow(*this->sub_iter_p); + return *this; + } + + Iterator(Iterator&&) = default; + Iterator& operator=(Iterator&&) = default; + ~Iterator() = default; + + Iterator& operator++() { + ++*this->sub_iter_p; + if (!(*this->sub_iter_p != *this->sub_end_p)) { + ++this->top_level_iter; + if (this->top_level_iter != this->top_level_end) { + sub_iter_p.reset(new SubIter{std::begin(*this->top_level_iter)}); + sub_end_p.reset(new SubIter{std::end(*this->top_level_iter)}); + } else { + sub_iter_p.reset(nullptr); + sub_end_p.reset(nullptr); + } } - }; + return *this; + } - Iterator begin() { - return {std::begin(this->container), std::end(this->container)}; + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; } - Iterator end() { - return {std::end(this->container), std::end(this->container)}; + bool operator!=(const Iterator& other) const { + return this->top_level_iter != other.top_level_iter + || this->sub_iters_differ(other); } - }; - class ChainMaker { - public: - // expose regular call operator to provide usual chain() - template - Chained operator()(Containers&&... cs) const { - return {std::forward(cs)...}; + bool operator==(const Iterator& other) const { + return !(*this != other); } - // chain.from_iterable - template - ChainedFromIterable from_iterable(Container&& container) const { - return {std::forward(container)}; + iterator_deref> operator*() { + return **this->sub_iter_p; + } + + iterator_arrow> operator->() { + return apply_arrow(*this->sub_iter_p); } }; - namespace { - constexpr auto chain = ChainMaker{}; + Iterator begin() { + return {std::begin(this->container), std::end(this->container)}; } -} + + Iterator end() { + return {std::end(this->container), std::end(this->container)}; + } +}; + +class iter::impl::ChainMaker { + public: + // expose regular call operator to provide usual chain() + template + Chained operator()(Containers&&... cs) const { + return {std::forward(cs)...}; + } + + // chain.from_iterable() + template + ChainedFromIterable from_iterable(Container&& container) const { + return {std::forward(container)}; + } +}; + +constexpr iter::impl::ChainMaker iter::chain{}; #endif From 2cea1fc939eccbf62b2330cb2c27fd81c8ebe430 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 09:22:16 -0700 Subject: [PATCH 1225/1866] moves Combinator into impl { } --- combinations.hpp | 202 ++++++++++++++++++++++++----------------------- 1 file changed, 102 insertions(+), 100 deletions(-) diff --git a/combinations.hpp b/combinations.hpp index 74b93829..83be1851 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -10,139 +10,141 @@ #include namespace iter { - template - class Combinator; + namespace impl { + template + class Combinator; + } template - Combinator combinations(Container&&, std::size_t); + impl::Combinator combinations(Container&&, std::size_t); template - Combinator> combinations( + impl::Combinator> combinations( std::initializer_list, std::size_t); +} - template - class Combinator { - private: - Container container; - std::size_t length; +template +class iter::impl::Combinator { + private: + Container container; + std::size_t length; - friend Combinator combinations(Container&&, std::size_t); - template - friend Combinator> combinations( - std::initializer_list, std::size_t); + friend Combinator iter::combinations(Container&&, std::size_t); + template + friend Combinator> iter::combinations( + std::initializer_list, std::size_t); - Combinator(Container&& in_container, std::size_t in_length) - : container(std::forward(in_container)), length{in_length} {} + Combinator(Container&& in_container, std::size_t in_length) + : container(std::forward(in_container)), length{in_length} {} - using IndexVector = std::vector>; - using CombIteratorDeref = IterIterWrapper; + using IndexVector = std::vector>; + using CombIteratorDeref = IterIterWrapper; + + public: + class Iterator + : public std::iterator { + private: + constexpr static const int COMPLETE = -1; + typename std::remove_reference::type* container_p; + CombIteratorDeref indices; + int steps{}; public: - class Iterator - : public std::iterator { - private: - constexpr static const int COMPLETE = -1; - typename std::remove_reference::type* container_p; - CombIteratorDeref indices; - int steps{}; - - public: - Iterator(Container& in_container, std::size_t n) - : container_p{&in_container}, indices{n} { - if (n == 0) { + Iterator(Container& in_container, std::size_t n) + : container_p{&in_container}, indices{n} { + if (n == 0) { + this->steps = COMPLETE; + return; + } + size_t inc = 0; + for (auto& iter : this->indices.get()) { + auto it = std::begin(*this->container_p); + dumb_advance(it, std::end(*this->container_p), inc); + if (it != std::end(*this->container_p)) { + iter = it; + ++inc; + } else { this->steps = COMPLETE; - return; - } - size_t inc = 0; - for (auto& iter : this->indices.get()) { - auto it = std::begin(*this->container_p); - dumb_advance(it, std::end(*this->container_p), inc); - if (it != std::end(*this->container_p)) { - iter = it; - ++inc; - } else { - this->steps = COMPLETE; - break; - } + break; } } + } - CombIteratorDeref& operator*() { - return this->indices; - } + CombIteratorDeref& operator*() { + return this->indices; + } - CombIteratorDeref* operator->() { - return &this->indices; - } + CombIteratorDeref* operator->() { + return &this->indices; + } - Iterator& operator++() { - for (auto iter = indices.get().rbegin(); iter != indices.get().rend(); - ++iter) { - ++(*iter); - - // what we have to check here is if the distance between - // the index and the end of indices is >= the distance - // between the item and end of item - auto dist = std::distance(this->indices.get().rbegin(), iter); - - if (!(dumb_next(*iter, dist) != std::end(*this->container_p))) { - if ((iter + 1) != indices.get().rend()) { - size_t inc = 1; - for (auto down = iter; down != indices.get().rbegin() - 1; - --down) { - (*down) = dumb_next(*(iter + 1), 1 + inc); - ++inc; - } - } else { - this->steps = COMPLETE; - break; + Iterator& operator++() { + for (auto iter = indices.get().rbegin(); iter != indices.get().rend(); + ++iter) { + ++(*iter); + + // what we have to check here is if the distance between + // the index and the end of indices is >= the distance + // between the item and end of item + auto dist = std::distance(this->indices.get().rbegin(), iter); + + if (!(dumb_next(*iter, dist) != std::end(*this->container_p))) { + if ((iter + 1) != indices.get().rend()) { + size_t inc = 1; + for (auto down = iter; down != indices.get().rbegin() - 1; --down) { + (*down) = dumb_next(*(iter + 1), 1 + inc); + ++inc; } } else { + this->steps = COMPLETE; break; } - // we break because none of the rest of the items need - // to be incremented - } - if (this->steps != COMPLETE) { - ++this->steps; + } else { + break; } - return *this; + // we break because none of the rest of the items need + // to be incremented } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - bool operator!=(const Iterator& other) const { - return !(*this == other); + if (this->steps != COMPLETE) { + ++this->steps; } + return *this; + } - bool operator==(const Iterator& other) const { - return this->steps == other.steps; - } - }; + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } - Iterator begin() { - return {this->container, this->length}; + bool operator!=(const Iterator& other) const { + return !(*this == other); } - Iterator end() { - return {this->container, 0}; + bool operator==(const Iterator& other) const { + return this->steps == other.steps; } }; - template - Combinator combinations( - Container&& container, std::size_t length) { - return {std::forward(container), length}; + Iterator begin() { + return {this->container, this->length}; } - template - Combinator> combinations( - std::initializer_list il, std::size_t length) { - return {std::move(il), length}; + Iterator end() { + return {this->container, 0}; } +}; + +template +iter::impl::Combinator iter::combinations( + Container&& container, std::size_t length) { + return {std::forward(container), length}; +} + +template +iter::impl::Combinator> iter::combinations( + std::initializer_list il, std::size_t length) { + return {std::move(il), length}; } + #endif From 75478b90707255ee205fb4510598100d3daf6b10 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 09:24:49 -0700 Subject: [PATCH 1226/1866] moves CombinatorWithReplacement into impl { } --- combinations_with_replacement.hpp | 173 +++++++++++++++--------------- 1 file changed, 87 insertions(+), 86 deletions(-) diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index d579d8ef..64c139ba 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -10,123 +10,124 @@ #include namespace iter { + namespace impl { + template + class CombinatorWithReplacement; + } template - class CombinatorWithReplacement; - - template - CombinatorWithReplacement combinations_with_replacement( + impl::CombinatorWithReplacement combinations_with_replacement( Container&&, std::size_t); template - CombinatorWithReplacement> + impl::CombinatorWithReplacement> combinations_with_replacement(std::initializer_list, std::size_t); +} - template - class CombinatorWithReplacement { - private: - Container container; - std::size_t length; +template +class iter::impl::CombinatorWithReplacement { + private: + Container container; + std::size_t length; - friend CombinatorWithReplacement combinations_with_replacement( - Container&&, std::size_t); - template - friend CombinatorWithReplacement> - combinations_with_replacement(std::initializer_list, std::size_t); + friend CombinatorWithReplacement + iter::combinations_with_replacement(Container&&, std::size_t); + template + friend CombinatorWithReplacement> + iter::combinations_with_replacement( + std::initializer_list, std::size_t); - CombinatorWithReplacement(Container&& in_container, std::size_t n) - : container(std::forward(in_container)), length{n} {} + CombinatorWithReplacement(Container&& in_container, std::size_t n) + : container(std::forward(in_container)), length{n} {} - using IndexVector = std::vector>; - using CombIteratorDeref = IterIterWrapper; + using IndexVector = std::vector>; + using CombIteratorDeref = IterIterWrapper; + + public: + class Iterator + : public std::iterator { + private: + constexpr static const int COMPLETE = -1; + typename std::remove_reference::type* container_p; + CombIteratorDeref indices; + int steps; public: - class Iterator - : public std::iterator { - private: - constexpr static const int COMPLETE = -1; - typename std::remove_reference::type* container_p; - CombIteratorDeref indices; - int steps; - - public: - Iterator(Container& in_container, std::size_t n) - : container_p{&in_container}, - indices(n, std::begin(in_container)), - steps{(std::begin(in_container) != std::end(in_container) && n) - ? 0 - : COMPLETE} {} - - CombIteratorDeref& operator*() { - return this->indices; - } + Iterator(Container& in_container, std::size_t n) + : container_p{&in_container}, + indices(n, std::begin(in_container)), + steps{(std::begin(in_container) != std::end(in_container) && n) + ? 0 + : COMPLETE} {} + + CombIteratorDeref& operator*() { + return this->indices; + } - CombIteratorDeref* operator->() { - return &this->indices; - } + CombIteratorDeref* operator->() { + return &this->indices; + } - Iterator& operator++() { - for (auto iter = indices.get().rbegin(); iter != indices.get().rend(); - ++iter) { - ++(*iter); - if (!(*iter != std::end(*this->container_p))) { - if ((iter + 1) != indices.get().rend()) { - for (auto down = iter; down != indices.get().rbegin() - 1; - --down) { - (*down) = dumb_next(*(iter + 1)); - } - } else { - this->steps = COMPLETE; - break; + Iterator& operator++() { + for (auto iter = indices.get().rbegin(); iter != indices.get().rend(); + ++iter) { + ++(*iter); + if (!(*iter != std::end(*this->container_p))) { + if ((iter + 1) != indices.get().rend()) { + for (auto down = iter; down != indices.get().rbegin() - 1; --down) { + (*down) = dumb_next(*(iter + 1)); } } else { - // we break because none of the rest of the items - // need to be incremented + this->steps = COMPLETE; break; } + } else { + // we break because none of the rest of the items + // need to be incremented + break; } - if (this->steps != COMPLETE) { - ++this->steps; - } - return *this; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; } - - bool operator!=(const Iterator& other) const { - return !(*this == other); + if (this->steps != COMPLETE) { + ++this->steps; } + return *this; + } - bool operator==(const Iterator& other) const { - return this->steps == other.steps; - } - }; + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } - Iterator begin() { - return {this->container, this->length}; + bool operator!=(const Iterator& other) const { + return !(*this == other); } - Iterator end() { - return {this->container, 0}; + bool operator==(const Iterator& other) const { + return this->steps == other.steps; } }; - template - CombinatorWithReplacement combinations_with_replacement( - Container&& container, std::size_t length) { - return {std::forward(container), length}; + Iterator begin() { + return {this->container, this->length}; } - template - CombinatorWithReplacement> - combinations_with_replacement( - std::initializer_list il, std::size_t length) { - return {std::move(il), length}; + Iterator end() { + return {this->container, 0}; } +}; + +template +iter::impl::CombinatorWithReplacement +iter::combinations_with_replacement(Container&& container, std::size_t length) { + return {std::forward(container), length}; +} + +template +iter::impl::CombinatorWithReplacement> +iter::combinations_with_replacement( + std::initializer_list il, std::size_t length) { + return {std::move(il), length}; } #endif From dc360f824bf8d18667f10cab6e80697e1c7a1038 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 09:39:46 -0700 Subject: [PATCH 1227/1866] moves Compressed into impl { } --- compress.hpp | 220 +++++++++++++++++++++++++-------------------------- 1 file changed, 109 insertions(+), 111 deletions(-) diff --git a/compress.hpp b/compress.hpp index 5089228d..d6ef8096 100644 --- a/compress.hpp +++ b/compress.hpp @@ -8,156 +8,154 @@ #include namespace iter { - - // Forward declarations of Compressed and compress - template - class Compressed; + namespace impl { + template + class Compressed; + } template - Compressed compress(Container&&, Selector&&); + impl::Compressed compress(Container&&, Selector&&); template - Compressed, Selector> compress( + impl::Compressed, Selector> compress( std::initializer_list, Selector&&); template - Compressed> compress( + impl::Compressed> compress( Container&&, std::initializer_list); template - Compressed, std::initializer_list> compress( + impl::Compressed, std::initializer_list> compress( std::initializer_list, std::initializer_list); +} - template - class Compressed { - private: - Container container; - Selector selectors; +template +class iter::impl::Compressed { + private: + Container container; + Selector selectors; - // The only thing allowed to directly instantiate an Compressed is - // the compress function - friend Compressed compress(Container&&, Selector&&); + friend Compressed iter::compress( + Container&&, Selector&&); - template - friend Compressed, Sel> compress( - std::initializer_list, Sel&&); + template + friend Compressed, Sel> iter::compress( + std::initializer_list, Sel&&); - template - friend Compressed> compress( - Con&&, std::initializer_list); + template + friend Compressed> iter::compress( + Con&&, std::initializer_list); - template - friend Compressed, std::initializer_list> - compress(std::initializer_list, std::initializer_list); + template + friend Compressed, std::initializer_list> + iter::compress(std::initializer_list, std::initializer_list); - // Selector::Iterator type - using selector_iter_type = decltype(std::begin(selectors)); + // Selector::Iterator type + using selector_iter_type = decltype(std::begin(selectors)); - // Value constructor for use only in the compress function - Compressed(Container&& in_container, Selector&& in_selectors) - : container(std::forward(in_container)), - selectors(std::forward(in_selectors)) {} + Compressed(Container&& in_container, Selector&& in_selectors) + : container(std::forward(in_container)), + selectors(std::forward(in_selectors)) {} - public: - class Iterator : public std::iterator> { - private: - iterator_type sub_iter; - iterator_type sub_end; - - selector_iter_type selector_iter; - selector_iter_type selector_end; - - void increment_iterators() { - ++this->sub_iter; - ++this->selector_iter; - } + public: + class Iterator : public std::iterator> { + private: + iterator_type sub_iter; + iterator_type sub_end; - void skip_failures() { - while (this->sub_iter != this->sub_end - && this->selector_iter != this->selector_end - && !*this->selector_iter) { - this->increment_iterators(); - } - } + selector_iter_type selector_iter; + selector_iter_type selector_end; - public: - Iterator(iterator_type&& cont_iter, - iterator_type&& cont_end, selector_iter_type&& sel_iter, - selector_iter_type&& sel_end) - : sub_iter{std::move(cont_iter)}, - sub_end{std::move(cont_end)}, - selector_iter{std::move(sel_iter)}, - selector_end{std::move(sel_end)} { - this->skip_failures(); - } + void increment_iterators() { + ++this->sub_iter; + ++this->selector_iter; + } - iterator_deref operator*() { - return *this->sub_iter; + void skip_failures() { + while (this->sub_iter != this->sub_end + && this->selector_iter != this->selector_end + && !*this->selector_iter) { + this->increment_iterators(); } + } - iterator_arrow operator->() { - return apply_arrow(this->sub_iter); - } + public: + Iterator(iterator_type&& cont_iter, + iterator_type&& cont_end, selector_iter_type&& sel_iter, + selector_iter_type&& sel_end) + : sub_iter{std::move(cont_iter)}, + sub_end{std::move(cont_end)}, + selector_iter{std::move(sel_iter)}, + selector_end{std::move(sel_end)} { + this->skip_failures(); + } - Iterator& operator++() { - this->increment_iterators(); - this->skip_failures(); - return *this; - } + iterator_deref operator*() { + return *this->sub_iter; + } - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } + iterator_arrow operator->() { + return apply_arrow(this->sub_iter); + } - bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter - && this->selector_iter != other.selector_iter; - } + Iterator& operator++() { + this->increment_iterators(); + this->skip_failures(); + return *this; + } - bool operator==(const Iterator& other) const { - return !(*this != other); - } - }; + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } - Iterator begin() { - return {std::begin(this->container), std::end(this->container), - std::begin(this->selectors), std::end(this->selectors)}; + bool operator!=(const Iterator& other) const { + return this->sub_iter != other.sub_iter + && this->selector_iter != other.selector_iter; } - Iterator end() { - return {std::end(this->container), std::end(this->container), - std::end(this->selectors), std::end(this->selectors)}; + bool operator==(const Iterator& other) const { + return !(*this != other); } }; - // Helper function to instantiate an Compressed - template - Compressed compress( - Container&& container, Selector&& selectors) { - return { - std::forward(container), std::forward(selectors)}; + Iterator begin() { + return {std::begin(this->container), std::end(this->container), + std::begin(this->selectors), std::end(this->selectors)}; } - template - Compressed, Selector> compress( - std::initializer_list data, Selector&& selectors) { - return {std::move(data), std::forward(selectors)}; + Iterator end() { + return {std::end(this->container), std::end(this->container), + std::end(this->selectors), std::end(this->selectors)}; } +}; - template - Compressed> compress( - Container&& container, std::initializer_list selectors) { - return {std::forward(container), std::move(selectors)}; - } +template +iter::impl::Compressed iter::compress( + Container&& container, Selector&& selectors) { + return { + std::forward(container), std::forward(selectors)}; +} - template - Compressed, std::initializer_list> compress( - std::initializer_list data, std::initializer_list selectors) { - return {std::move(data), std::move(selectors)}; - } +template +iter::impl::Compressed, Selector> iter::compress( + std::initializer_list data, Selector&& selectors) { + return {std::move(data), std::forward(selectors)}; +} + +template +iter::impl::Compressed> iter::compress( + Container&& container, std::initializer_list selectors) { + return {std::forward(container), std::move(selectors)}; +} + +template +iter::impl::Compressed, std::initializer_list> +iter::compress( + std::initializer_list data, std::initializer_list selectors) { + return {std::move(data), std::move(selectors)}; } #endif From 209424b8c0cbf9ccbda8f9fd0493e8533500bcf6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 21:04:30 -0700 Subject: [PATCH 1228/1866] moves Cycler into impl { } --- cycle.hpp | 125 +++++++++++++++++++++++++++--------------------------- 1 file changed, 63 insertions(+), 62 deletions(-) diff --git a/cycle.hpp b/cycle.hpp index 84e0c314..07356032 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -8,92 +8,93 @@ #include namespace iter { + namespace impl { + template + class Cycler; + } template - class Cycle; + impl::Cycler cycle(Container&&); - template - Cycle cycle(Container&&); + template + impl::Cycler> cycle(std::initializer_list); +} +template +class iter::impl::Cycler { + private: + friend Cycler iter::cycle(Container&&); template - Cycle> cycle(std::initializer_list); + friend Cycler> iter::cycle(std::initializer_list); - template - class Cycle { - private: - friend Cycle cycle(Container&&); - template - friend Cycle> cycle(std::initializer_list); + Container container; - Container container; + Cycler(Container&& in_container) + : container(std::forward(in_container)) {} - Cycle(Container&& in_container) - : container(std::forward(in_container)) {} + public: + class Iterator : public std::iterator> { + private: + iterator_type sub_iter; + iterator_type begin; + iterator_type end; public: - class Iterator : public std::iterator> { - private: - using iter_type = iterator_type; - iterator_type sub_iter; - iterator_type begin; - iterator_type end; - - public: - Iterator(const iterator_type& iter, - iterator_type&& in_end) - : sub_iter{iter}, begin{iter}, end{std::move(in_end)} {} - - iterator_deref operator*() { - return *this->sub_iter; - } + Iterator( + const iterator_type& iter, iterator_type&& in_end) + : sub_iter{iter}, begin{iter}, end{std::move(in_end)} {} - iterator_arrow operator->() { - return apply_arrow(this->sub_iter); - } - - Iterator& operator++() { - ++this->sub_iter; - // reset to beginning upon reaching the end - if (!(this->sub_iter != this->end)) { - this->sub_iter = this->begin; - } - return *this; - } + iterator_deref operator*() { + return *this->sub_iter; + } - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } + iterator_arrow operator->() { + return apply_arrow(this->sub_iter); + } - bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter; + Iterator& operator++() { + ++this->sub_iter; + // reset to beginning upon reaching the end + if (!(this->sub_iter != this->end)) { + this->sub_iter = this->begin; } + return *this; + } - bool operator==(const Iterator& other) const { - return !(*this != other); - } - }; + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } - Iterator begin() { - return {std::begin(this->container), std::end(this->container)}; + bool operator!=(const Iterator& other) const { + return this->sub_iter != other.sub_iter; } - Iterator end() { - return {std::end(this->container), std::end(this->container)}; + bool operator==(const Iterator& other) const { + return !(*this != other); } }; - template - Cycle cycle(Container&& container) { - return {std::forward(container)}; + Iterator begin() { + return {std::begin(this->container), std::end(this->container)}; } - template - Cycle> cycle(std::initializer_list il) { - return {std::move(il)}; + Iterator end() { + return {std::end(this->container), std::end(this->container)}; } +}; + +template +iter::impl::Cycler iter::cycle(Container&& container) { + return {std::forward(container)}; +} + +template +iter::impl::Cycler> iter::cycle( + std::initializer_list il) { + return {std::move(il)}; } #endif From e5838b2f0b4ddf606b58b6c4aa8f9f0010c64e55 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 21:18:35 -0700 Subject: [PATCH 1229/1866] moves Dropper into impl{ } --- dropwhile.hpp | 174 +++++++++++++++++++++++++------------------------- 1 file changed, 88 insertions(+), 86 deletions(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index 073234de..9efbdbc3 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -8,120 +8,122 @@ #include namespace iter { + namespace impl { + template + class Dropper; + } template - class DropWhile; - - template - DropWhile dropwhile(FilterFunc, Container&&); + impl::Dropper dropwhile(FilterFunc, Container&&); template - DropWhile> dropwhile( + impl::Dropper> dropwhile( FilterFunc, std::initializer_list); +} - template - class DropWhile { - private: - Container container; - FilterFunc filter_func; - - friend DropWhile dropwhile(FilterFunc, Container&&); - - template - friend DropWhile> dropwhile( - FF, std::initializer_list); +template +class iter::impl::Dropper { + private: + Container container; + FilterFunc filter_func; - DropWhile(FilterFunc in_filter_func, Container&& in_container) - : container(std::forward(in_container)), - filter_func(in_filter_func) {} + friend Dropper iter::dropwhile( + FilterFunc, Container&&); - public: - class Iterator : public std::iterator> { - private: - using Holder = DerefHolder>; - iterator_type sub_iter; - iterator_type sub_end; - Holder item; - FilterFunc* filter_func; - - void inc_sub_iter() { - ++this->sub_iter; - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); - } - } + template + friend Dropper> iter::dropwhile( + FF, std::initializer_list); - // skip all values for which the predicate is true - void skip_passes() { - while (this->sub_iter != this->sub_end - && (*this->filter_func)(this->item.get())) { - this->inc_sub_iter(); - } - } + Dropper(FilterFunc in_filter_func, Container&& in_container) + : container(std::forward(in_container)), + filter_func(in_filter_func) {} - public: - Iterator(iterator_type&& iter, iterator_type&& end, - FilterFunc& in_filter_func) - : sub_iter{std::move(iter)}, - sub_end{std::move(end)}, - filter_func(&in_filter_func) { - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); - } - this->skip_passes(); + public: + class Iterator : public std::iterator> { + private: + using Holder = DerefHolder>; + iterator_type sub_iter; + iterator_type sub_end; + Holder item; + FilterFunc* filter_func; + + void inc_sub_iter() { + ++this->sub_iter; + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); } + } - typename Holder::reference operator*() { - return this->item.get(); + // skip all values for which the predicate is true + void skip_passes() { + while (this->sub_iter != this->sub_end + && (*this->filter_func)(this->item.get())) { + this->inc_sub_iter(); } + } - typename Holder::pointer operator->() { - return this->item.get_ptr(); + public: + Iterator(iterator_type&& iter, iterator_type&& end, + FilterFunc& in_filter_func) + : sub_iter{std::move(iter)}, + sub_end{std::move(end)}, + filter_func(&in_filter_func) { + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); } + this->skip_passes(); + } - Iterator& operator++() { - this->inc_sub_iter(); - return *this; - } + typename Holder::reference operator*() { + return this->item.get(); + } - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } + typename Holder::pointer operator->() { + return this->item.get_ptr(); + } - bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter; - } + Iterator& operator++() { + this->inc_sub_iter(); + return *this; + } - bool operator==(const Iterator& other) const { - return !(*this != other); - } - }; + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } - Iterator begin() { - return {std::begin(this->container), std::end(this->container), - this->filter_func}; + bool operator!=(const Iterator& other) const { + return this->sub_iter != other.sub_iter; } - Iterator end() { - return {std::end(this->container), std::end(this->container), - this->filter_func}; + bool operator==(const Iterator& other) const { + return !(*this != other); } }; - template - DropWhile dropwhile( - FilterFunc filter_func, Container&& container) { - return {filter_func, std::forward(container)}; + Iterator begin() { + return {std::begin(this->container), std::end(this->container), + this->filter_func}; } - template - DropWhile> dropwhile( - FilterFunc filter_func, std::initializer_list il) { - return {filter_func, std::move(il)}; + Iterator end() { + return {std::end(this->container), std::end(this->container), + this->filter_func}; } +}; + +template +iter::impl::Dropper iter::dropwhile( + FilterFunc filter_func, Container&& container) { + return {filter_func, std::forward(container)}; +} + +template +iter::impl::Dropper> iter::dropwhile( + FilterFunc filter_func, std::initializer_list il) { + return {filter_func, std::move(il)}; } #endif From 99cae928d3b501a1a1dd7ad8ab1432af15760854 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 21:26:56 -0700 Subject: [PATCH 1230/1866] moves Filtered into impl { } --- filter.hpp | 189 +++++++++++++++++++++++++++-------------------------- 1 file changed, 95 insertions(+), 94 deletions(-) diff --git a/filter.hpp b/filter.hpp index 89e38531..9a7b203f 100644 --- a/filter.hpp +++ b/filter.hpp @@ -8,125 +8,126 @@ #include namespace iter { - - // Forward declarations of Filter and filter - template - class Filter; + namespace impl { + template + class Filtered; + } template - Filter filter(FilterFunc, Container&&); + impl::Filtered filter(FilterFunc, Container&&); template - Filter> filter( + impl::Filtered> filter( FilterFunc, std::initializer_list); +} - template - class Filter { - private: - Container container; - FilterFunc filter_func; - - // The filter function is the only thing allowed to create a Filter - friend Filter filter(FilterFunc, Container&&); - - template - friend Filter> filter( - FF, std::initializer_list); - - // Value constructor for use only in the filter function - Filter(FilterFunc in_filter_func, Container&& in_container) - : container(std::forward(in_container)), - filter_func(in_filter_func) {} - - public: - class Iterator : public std::iterator> { - protected: - using Holder = DerefHolder>; - iterator_type sub_iter; - iterator_type sub_end; - Holder item; - FilterFunc* filter_func; - - void inc_sub_iter() { - ++this->sub_iter; - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); - } - } - - // increment until the iterator points to is true on the - // predicate. Called by constructor and operator++ - void skip_failures() { - while (this->sub_iter != this->sub_end - && !(*this->filter_func)(this->item.get())) { - this->inc_sub_iter(); - } - } - - public: - Iterator(iterator_type iter, iterator_type end, - FilterFunc& in_filter_func) - : sub_iter{iter}, sub_end{end}, filter_func(&in_filter_func) { - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); - } - this->skip_failures(); +template +class iter::impl::Filtered { + private: + Container container; + FilterFunc filter_func; + + // The filter function is the only thing allowed to create a Filtered + friend Filtered iter::filter(FilterFunc, Container&&); + + template + friend Filtered> iter::filter( + FF, std::initializer_list); + + // Value constructor for use only in the filter function + Filtered(FilterFunc in_filter_func, Container&& in_container) + : container(std::forward(in_container)), + filter_func(in_filter_func) {} + + public: + class Iterator : public std::iterator> { + protected: + using Holder = DerefHolder>; + iterator_type sub_iter; + iterator_type sub_end; + Holder item; + FilterFunc* filter_func; + + void inc_sub_iter() { + ++this->sub_iter; + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); } + } - typename Holder::reference operator*() { - return this->item.get(); + // increment until the iterator points to is true on the + // predicate. Called by constructor and operator++ + void skip_failures() { + while (this->sub_iter != this->sub_end + && !(*this->filter_func)(this->item.get())) { + this->inc_sub_iter(); } + } - typename Holder::pointer operator->() { - return this->item.get_ptr(); + public: + Iterator(iterator_type iter, iterator_type end, + FilterFunc& in_filter_func) + : sub_iter{iter}, sub_end{end}, filter_func(&in_filter_func) { + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); } + this->skip_failures(); + } - Iterator& operator++() { - this->inc_sub_iter(); - this->skip_failures(); - return *this; - } + typename Holder::reference operator*() { + return this->item.get(); + } - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } + typename Holder::pointer operator->() { + return this->item.get_ptr(); + } - bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter; - } + Iterator& operator++() { + this->inc_sub_iter(); + this->skip_failures(); + return *this; + } - bool operator==(const Iterator& other) const { - return !(*this != other); - } - }; + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } - Iterator begin() { - return {std::begin(this->container), std::end(this->container), - this->filter_func}; + bool operator!=(const Iterator& other) const { + return this->sub_iter != other.sub_iter; } - Iterator end() { - return {std::end(this->container), std::end(this->container), - this->filter_func}; + bool operator==(const Iterator& other) const { + return !(*this != other); } }; - // Helper function to instantiate a Filter - template - Filter filter( - FilterFunc filter_func, Container&& container) { - return {filter_func, std::forward(container)}; + Iterator begin() { + return {std::begin(this->container), std::end(this->container), + this->filter_func}; } - template - Filter> filter( - FilterFunc filter_func, std::initializer_list il) { - return {filter_func, std::move(il)}; + Iterator end() { + return {std::end(this->container), std::end(this->container), + this->filter_func}; } +}; +template +iter::impl::Filtered iter::filter( + FilterFunc filter_func, Container&& container) { + return {filter_func, std::forward(container)}; +} + +template +iter::impl::Filtered> iter::filter( + FilterFunc filter_func, std::initializer_list il) { + return {filter_func, std::move(il)}; +} + +namespace iter { namespace detail { template From 7268b1b8f0ffe0602ae36bddf364959a87b3fbd7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 21:32:26 -0700 Subject: [PATCH 1231/1866] resolves chain link error --- chain.hpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/chain.hpp b/chain.hpp index 7c5308ea..0e8c3343 100644 --- a/chain.hpp +++ b/chain.hpp @@ -24,8 +24,6 @@ namespace iter { // .from_iterable() class ChainMaker; } - - extern const impl::ChainMaker chain; } template @@ -307,6 +305,10 @@ class iter::impl::ChainMaker { } }; -constexpr iter::impl::ChainMaker iter::chain{}; +namespace iter { + namespace { + constexpr auto chain = impl::ChainMaker{}; + } +} #endif From c1ecea13acec919791fadcbf25783902fcd2d92e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 21:33:35 -0700 Subject: [PATCH 1232/1866] adjusts for Filtered rename --- unique_everseen.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/unique_everseen.hpp b/unique_everseen.hpp index b971ca62..23b951c4 100644 --- a/unique_everseen.hpp +++ b/unique_everseen.hpp @@ -15,7 +15,8 @@ namespace iter { // performance checking if it has ever been seen template auto unique_everseen(Container&& container) - -> Filter)>, Container> { + -> impl::Filtered)>, + Container> { using elem_t = iterator_deref; std::unordered_set::type> elem_seen; @@ -35,7 +36,7 @@ namespace iter { template auto unique_everseen(std::initializer_list il) - -> Filter, std::initializer_list> { + -> impl::Filtered, 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)) { From 65917212349b0ddc6f50f32c898ce3cd535e6d42 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 21:49:47 -0700 Subject: [PATCH 1233/1866] moves GroupProducer into impl { } --- groupby.hpp | 456 ++++++++++++++++++++++++++-------------------------- 1 file changed, 231 insertions(+), 225 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index c6d758a1..8262652b 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -12,301 +12,307 @@ #include namespace iter { - - template - class GroupBy; - + namespace impl { + template + class GroupProducer; + } template - GroupBy groupby(Container&&, KeyFunc); + impl::GroupProducer groupby(Container&&, KeyFunc); template - GroupBy, KeyFunc> groupby( + impl::GroupProducer, KeyFunc> groupby( std::initializer_list, KeyFunc); +} - template - class GroupBy { - private: - Container container; - KeyFunc key_func; +template +class iter::impl::GroupProducer { + private: + Container container; + KeyFunc key_func; - friend GroupBy groupby(Container&&, KeyFunc); + friend GroupProducer iter::groupby(Container&&, KeyFunc); - template - friend GroupBy, KF> groupby( - std::initializer_list, KF); + template + friend GroupProducer, KF> iter::groupby( + std::initializer_list, KF); - using key_func_ret = - typename std::result_of)>::type; + using key_func_ret = + typename std::result_of)>::type; - GroupBy(Container&& in_container, KeyFunc in_key_func) - : container(std::forward(in_container)), - key_func(in_key_func) {} + GroupProducer(Container&& in_container, KeyFunc in_key_func) + : container(std::forward(in_container)), + key_func(in_key_func) {} - public: - GroupBy() = delete; - GroupBy(const GroupBy&) = delete; - GroupBy& operator=(const GroupBy&) = delete; - GroupBy& operator=(GroupBy&&) = delete; + public: + GroupProducer() = delete; + GroupProducer(const GroupProducer&) = delete; + GroupProducer& operator=(const GroupProducer&) = delete; + GroupProducer& operator=(GroupProducer&&) = delete; - GroupBy(GroupBy&&) = default; + GroupProducer(GroupProducer&&) = default; - class Iterator; - class Group; + class Iterator; + class Group; - private: - using KeyGroupPair = std::pair; - using Holder = DerefHolder>; + private: + using KeyGroupPair = std::pair; + using Holder = DerefHolder>; - public: - class Iterator - : public std::iterator { - private: - iterator_type sub_iter; - iterator_type sub_end; - Holder item; - KeyFunc* key_func; + public: + class Iterator : public std::iterator { + private: + iterator_type sub_iter; + iterator_type sub_end; + Holder item; + KeyFunc* key_func; - std::unique_ptr current_key_group_pair; + std::unique_ptr current_key_group_pair; - public: - Iterator(iterator_type&& si, iterator_type&& end, - KeyFunc& in_key_func) - : sub_iter{std::move(si)}, - sub_end{std::move(end)}, - key_func(&in_key_func) { - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); - } + public: + Iterator(iterator_type&& si, iterator_type&& end, + KeyFunc& in_key_func) + : sub_iter{std::move(si)}, + sub_end{std::move(end)}, + key_func(&in_key_func) { + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); } + } - Iterator(const Iterator& other) - : sub_iter{other.sub_iter}, - sub_end{other.sub_end}, - item{other.item}, - key_func{other.key_func} {} - - Iterator& operator=(const Iterator& other) { - if (this == &other) return *this; - this->sub_iter = other.sub_iter; - this->sub_end = other.sub_end; - this->item = other.item; - this->key_func = other.key_func; - this->current_key_group_pair.reset(); - return *this; - } + Iterator(const Iterator& other) + : sub_iter{other.sub_iter}, + sub_end{other.sub_end}, + item{other.item}, + key_func{other.key_func} {} + + Iterator& operator=(const Iterator& other) { + if (this == &other) return *this; + this->sub_iter = other.sub_iter; + this->sub_end = other.sub_end; + this->item = other.item; + this->key_func = other.key_func; + this->current_key_group_pair.reset(); + return *this; + } - ~Iterator() = default; + ~Iterator() = default; - // NOTE the implicitly generated move constructor would - // be wrong + // NOTE the implicitly generated move constructor would + // be wrong - KeyGroupPair& operator*() { - set_key_group_pair(); - return *this->current_key_group_pair; - } + KeyGroupPair& operator*() { + set_key_group_pair(); + return *this->current_key_group_pair; + } - KeyGroupPair* operator->() { - set_key_group_pair(); - return this->current_key_group_pair.get(); - } + KeyGroupPair* operator->() { + set_key_group_pair(); + return this->current_key_group_pair.get(); + } - Iterator& operator++() { - if (!this->current_key_group_pair) { - this->set_key_group_pair(); - } - this->current_key_group_pair.reset(); - return *this; + Iterator& operator++() { + if (!this->current_key_group_pair) { + this->set_key_group_pair(); } + this->current_key_group_pair.reset(); + return *this; + } - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } + 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->sub_iter != other.sub_iter; + } - bool operator==(const Iterator& other) const { - return !(*this != other); - } + bool operator==(const Iterator& other) const { + return !(*this != other); + } - void increment_iterator() { + void increment_iterator() { + if (this->sub_iter != this->sub_end) { + ++this->sub_iter; if (this->sub_iter != this->sub_end) { - ++this->sub_iter; - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); - } + this->item.reset(*this->sub_iter); } } + } - bool exhausted() const { - return !(this->sub_iter != this->sub_end); - } + bool exhausted() const { + return !(this->sub_iter != this->sub_end); + } - typename Holder::reference get() { - return this->item.get(); - } + typename Holder::reference get() { + return this->item.get(); + } - typename Holder::pointer get_ptr() { - return this->item.get_ptr(); - } + typename Holder::pointer get_ptr() { + return this->item.get_ptr(); + } - key_func_ret next_key() { - return (*this->key_func)(this->item.get()); - } + key_func_ret next_key() { + return (*this->key_func)(this->item.get()); + } - void set_key_group_pair() { - if (!this->current_key_group_pair) { - this->current_key_group_pair.reset( - new KeyGroupPair((*this->key_func)(this->item.get()), - Group{*this, this->next_key()})); - } + void set_key_group_pair() { + if (!this->current_key_group_pair) { + this->current_key_group_pair.reset( + new KeyGroupPair((*this->key_func)(this->item.get()), + Group{*this, this->next_key()})); } - }; + } + }; - class Group { - private: - friend Iterator; - friend class GroupIterator; - Iterator& owner; - key_func_ret key; - - // completed is set if a Group is iterated through - // completely. It is checked in the destructor, and - // if the Group has not been completed, the destructor - // exhausts it. This ensures that the next Group starts - // at the correct position when the user short-circuits - // iteration over a Group. - // The move constructor sets the rvalue's completed - // attribute to true, so its destructor doesn't do anything - // when called. - bool completed = false; - - Group(Iterator& in_owner, key_func_ret in_key) - : owner(in_owner), key(in_key) {} + class Group { + private: + friend Iterator; + friend class GroupIterator; + Iterator& owner; + key_func_ret key; + + // completed is set if a Group is iterated through + // completely. It is checked in the destructor, and + // if the Group has not been completed, the destructor + // exhausts it. This ensures that the next Group starts + // at the correct position when the user short-circuits + // iteration over a Group. + // The move constructor sets the rvalue's completed + // attribute to true, so its destructor doesn't do anything + // when called. + bool completed = false; + + Group(Iterator& in_owner, key_func_ret in_key) + : owner(in_owner), key(in_key) {} - public: - ~Group() { - if (!this->completed) { - for (auto iter = this->begin(), end = this->end(); iter != end; - ++iter) { - } + public: + ~Group() { + if (!this->completed) { + for (auto iter = this->begin(), end = this->end(); iter != end; + ++iter) { } } + } - // move-constructible, non-copy-constructible, - // non-assignable - Group() = delete; - Group(const Group&) = default; - Group& operator=(const Group&) = delete; - Group& operator=(Group&&) = delete; - - Group(Group&& other) - : owner{other.owner}, key{other.key}, completed{other.completed} { - other.completed = true; - } - - class GroupIterator : public std::iterator> { - private: - typename std::remove_reference::type* key; - Group* group_p; + // move-constructible, non-copy-constructible, + // non-assignable + Group() = delete; + Group(const Group&) = default; + Group& operator=(const Group&) = delete; + Group& operator=(Group&&) = delete; - bool not_at_end() { - return !this->group_p->owner.exhausted() - && this->group_p->owner.next_key() == *this->key; - } + Group(Group&& other) + : owner{other.owner}, key{other.key}, completed{other.completed} { + other.completed = true; + } - public: - GroupIterator(Group* in_group_p, key_func_ret& in_key) - : key{&in_key}, group_p{in_group_p} {} + class GroupIterator : public std::iterator> { + private: + typename std::remove_reference::type* key; + Group* group_p; - bool operator!=(const GroupIterator& other) const { - return !(*this == other); - } + bool not_at_end() { + return !this->group_p->owner.exhausted() + && this->group_p->owner.next_key() == *this->key; + } - bool operator==(const GroupIterator& other) const { - return this->group_p == other.group_p; - } + public: + GroupIterator(Group* in_group_p, key_func_ret& in_key) + : key{&in_key}, group_p{in_group_p} {} - GroupIterator& operator++() { - this->group_p->owner.increment_iterator(); - if (!this->not_at_end()) { - this->group_p->completed = true; - this->group_p = nullptr; - } - return *this; - } + bool operator!=(const GroupIterator& other) const { + return !(*this == other); + } - GroupIterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } + bool operator==(const GroupIterator& other) const { + return this->group_p == other.group_p; + } - iterator_deref operator*() { - return this->group_p->owner.get(); + GroupIterator& operator++() { + this->group_p->owner.increment_iterator(); + if (!this->not_at_end()) { + this->group_p->completed = true; + this->group_p = nullptr; } + return *this; + } - typename Holder::pointer operator->() { - return this->group_p->owner.get_ptr(); - } - }; + GroupIterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } - GroupIterator begin() { - return {this, key}; + iterator_deref operator*() { + return this->group_p->owner.get(); } - GroupIterator end() { - return {nullptr, key}; + typename Holder::pointer operator->() { + return this->group_p->owner.get_ptr(); } }; - Iterator begin() { - return {std::begin(this->container), std::end(this->container), - this->key_func}; + GroupIterator begin() { + return {this, key}; } - Iterator end() { - return { - std::end(this->container), std::end(this->container), this->key_func}; + GroupIterator end() { + return {nullptr, key}; } }; - // Takes something and returns it, used for default key of comparing - // items in the sequence directly - template - class ItemReturner { - public: - iterator_deref operator()(iterator_deref item) const { - return item; - } - }; + Iterator begin() { + return { + std::begin(this->container), std::end(this->container), this->key_func}; + } - template - GroupBy groupby(Container&& container, KeyFunc key_func) { - return {std::forward(container), key_func}; + Iterator end() { + return { + std::end(this->container), std::end(this->container), this->key_func}; } +}; - template - auto groupby(Container&& container) -> decltype( - groupby(std::forward(container), ItemReturner())) { - return groupby( - std::forward(container), ItemReturner()); +template +iter::impl::GroupProducer iter::groupby( + Container&& container, KeyFunc key_func) { + return {std::forward(container), key_func}; +} + +template +iter::impl::GroupProducer, KeyFunc> iter::groupby( + std::initializer_list il, KeyFunc key_func) { + return {std::move(il), key_func}; +} + +namespace iter { + namespace detail { + // Takes something and returns it, used for default key of comparing + // items in the sequence directly + template + class ItemReturner { + public: + iterator_deref operator()( + iterator_deref item) const { + return item; + } + }; } - template - GroupBy, KeyFunc> groupby( - std::initializer_list il, KeyFunc key_func) { - return {std::move(il), key_func}; + template + auto groupby(Container&& container) -> decltype(groupby( + std::forward(container), detail::ItemReturner())) { + return groupby( + std::forward(container), detail::ItemReturner()); } template - auto groupby(std::initializer_list il) -> decltype( - groupby(std::move(il), ItemReturner>())) { - return groupby(std::move(il), ItemReturner>()); + auto groupby(std::initializer_list il) -> decltype(groupby( + std::move(il), detail::ItemReturner>())) { + return groupby( + std::move(il), detail::ItemReturner>()); } } From a8164f8efd078a8b8f273df8cfc60ab71244e420 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 21:52:13 -0700 Subject: [PATCH 1234/1866] moves Grouper into impl { } --- grouper.hpp | 165 ++++++++++++++++++++++++++-------------------------- 1 file changed, 84 insertions(+), 81 deletions(-) diff --git a/grouper.hpp b/grouper.hpp index 0c6abd09..cb674111 100644 --- a/grouper.hpp +++ b/grouper.hpp @@ -13,113 +13,116 @@ #include namespace iter { - template - class Grouper; + namespace impl { + template + class Grouper; + } template - Grouper grouper(Container&&, std::size_t); + impl::Grouper grouper(Container&&, std::size_t); template - Grouper> grouper( + impl::Grouper> grouper( std::initializer_list, std::size_t); +} - template - class Grouper { - private: - Container container; - std::size_t group_size; - - Grouper(Container&& c, std::size_t sz) - : container(std::forward(c)), group_size{sz} {} +template +class iter::impl::Grouper { + private: + Container container; + std::size_t group_size; - friend Grouper grouper(Container&&, std::size_t); - template - friend Grouper> grouper( - std::initializer_list, std::size_t); + Grouper(Container&& c, std::size_t sz) + : container(std::forward(c)), group_size{sz} {} - using IndexVector = std::vector>; - using DerefVec = IterIterWrapper; + friend Grouper iter::grouper(Container&&, std::size_t); + template + friend Grouper> iter::grouper( + std::initializer_list, std::size_t); - public: - class Iterator : public std::iterator { - private: - iterator_type sub_iter; - iterator_type sub_end; - DerefVec group; - std::size_t group_size = 0; - - bool done() const { - return this->group.empty(); - } + using IndexVector = std::vector>; + using DerefVec = IterIterWrapper; - void refill_group() { - this->group.get().clear(); - std::size_t i{0}; - while (i < group_size && this->sub_iter != this->sub_end) { - group.get().push_back(this->sub_iter); - ++this->sub_iter; - ++i; - } - } + public: + class Iterator : public std::iterator { + private: + iterator_type sub_iter; + iterator_type sub_end; + DerefVec group; + std::size_t group_size = 0; - public: - Iterator(iterator_type&& in_iter, - iterator_type&& in_end, std::size_t s) - : sub_iter{std::move(in_iter)}, - sub_end{std::move(in_end)}, - group_size{s} { - this->group.get().reserve(this->group_size); - this->refill_group(); - } + bool done() const { + return this->group.empty(); + } - Iterator& operator++() { - this->refill_group(); - return *this; + void refill_group() { + this->group.get().clear(); + std::size_t i{0}; + while (i < group_size && this->sub_iter != this->sub_end) { + group.get().push_back(this->sub_iter); + ++this->sub_iter; + ++i; } + } - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } + public: + Iterator(iterator_type&& in_iter, + iterator_type&& in_end, std::size_t s) + : sub_iter{std::move(in_iter)}, + sub_end{std::move(in_end)}, + group_size{s} { + this->group.get().reserve(this->group_size); + this->refill_group(); + } - bool operator!=(const Iterator& other) const { - return !(*this == other); - } + Iterator& operator++() { + this->refill_group(); + return *this; + } - bool operator==(const Iterator& other) const { - return this->done() == other.done() - && (this->done() || !(this->sub_iter != other.sub_iter)); - } + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } - DerefVec& operator*() { - return this->group; - } + bool operator!=(const Iterator& other) const { + return !(*this == other); + } - DerefVec* operator->() { - return &this->group; - } - }; + bool operator==(const Iterator& other) const { + return this->done() == other.done() + && (this->done() || !(this->sub_iter != other.sub_iter)); + } - Iterator begin() { - return { - std::begin(this->container), std::end(this->container), group_size}; + DerefVec& operator*() { + return this->group; } - Iterator end() { - return {std::end(this->container), std::end(this->container), group_size}; + DerefVec* operator->() { + return &this->group; } }; - template - Grouper grouper(Container&& container, std::size_t group_size) { - return {std::forward(container), group_size}; + Iterator begin() { + return {std::begin(this->container), std::end(this->container), group_size}; } - template - Grouper> grouper( - std::initializer_list il, std::size_t group_size) { - return {std::move(il), group_size}; + Iterator end() { + return {std::end(this->container), std::end(this->container), group_size}; } +}; + +template +iter::impl::Grouper iter::grouper( + Container&& container, std::size_t group_size) { + return {std::forward(container), group_size}; +} + +template +iter::impl::Grouper> iter::grouper( + std::initializer_list il, std::size_t group_size) { + return {std::move(il), group_size}; } + #endif From 71e3620205fb7cc5e28547de2146aa9952af9da3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 22:03:59 -0700 Subject: [PATCH 1235/1866] Renames grouper() to chunked() I've wanted to do this from the beginning. It's not a very useful tool to begin with imo, but the name grouper() doesn't tell you anything. --- README.md | 8 +-- grouper.hpp => chunked.hpp | 64 ++++++++++----------- itertools.hpp | 2 +- test/SConstruct | 2 +- test/{test_grouper.cpp => test_chunked.cpp} | 28 ++++----- 5 files changed, 52 insertions(+), 52 deletions(-) rename grouper.hpp => chunked.hpp (59%) rename test/{test_grouper.cpp => test_chunked.cpp} (63%) diff --git a/README.md b/README.md index 02a6ba6e..26678192 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ evaluation wherever possible. [reversed](#reversed)
[slice](#slice)
[sliding\_window](#sliding_window)
-[grouper](#grouper)
+[chunked](#chunked)
##### Combinatoric fuctions [product](#product)
@@ -611,16 +611,16 @@ for (auto&& sec : sliding_window(v,4)) { cout << '\n'; } ``` -grouper +chunked ------ -grouper is very similar to sliding window, except instead of the +chunked is very similar to sliding window, except instead of the section sliding by only 1 it goes the length of the full section. Example usage: ```c++ vector v {1,2,3,4,5,6,7,8,9}; -for (auto&& sec : grouper(v,4)) +for (auto&& sec : chunked(v,4)) //each section will have 4 elements //except the last one may be cut short { diff --git a/grouper.hpp b/chunked.hpp similarity index 59% rename from grouper.hpp rename to chunked.hpp index cb674111..5b5981aa 100644 --- a/grouper.hpp +++ b/chunked.hpp @@ -1,5 +1,5 @@ -#ifndef ITER_GROUPER_HPP_ -#define ITER_GROUPER_HPP_ +#ifndef ITER_CHUNKED_HPP_ +#define ITER_CHUNKED_HPP_ #include "iterbase.hpp" #include "iteratoriterator.hpp" @@ -15,29 +15,29 @@ namespace iter { namespace impl { template - class Grouper; + class Chunker; } template - impl::Grouper grouper(Container&&, std::size_t); + impl::Chunker chunked(Container&&, std::size_t); template - impl::Grouper> grouper( + impl::Chunker> chunked( std::initializer_list, std::size_t); } template -class iter::impl::Grouper { +class iter::impl::Chunker { private: Container container; - std::size_t group_size; + std::size_t chunk_size; - Grouper(Container&& c, std::size_t sz) - : container(std::forward(c)), group_size{sz} {} + Chunker(Container&& c, std::size_t sz) + : container(std::forward(c)), chunk_size{sz} {} - friend Grouper iter::grouper(Container&&, std::size_t); + friend Chunker iter::chunked(Container&&, std::size_t); template - friend Grouper> iter::grouper( + friend Chunker> iter::chunked( std::initializer_list, std::size_t); using IndexVector = std::vector>; @@ -48,18 +48,18 @@ class iter::impl::Grouper { private: iterator_type sub_iter; iterator_type sub_end; - DerefVec group; - std::size_t group_size = 0; + DerefVec chunk; + std::size_t chunk_size = 0; bool done() const { - return this->group.empty(); + return this->chunk.empty(); } - void refill_group() { - this->group.get().clear(); + void refill_chunk() { + this->chunk.get().clear(); std::size_t i{0}; - while (i < group_size && this->sub_iter != this->sub_end) { - group.get().push_back(this->sub_iter); + while (i < chunk_size && this->sub_iter != this->sub_end) { + chunk.get().push_back(this->sub_iter); ++this->sub_iter; ++i; } @@ -70,13 +70,13 @@ class iter::impl::Grouper { iterator_type&& in_end, std::size_t s) : sub_iter{std::move(in_iter)}, sub_end{std::move(in_end)}, - group_size{s} { - this->group.get().reserve(this->group_size); - this->refill_group(); + chunk_size{s} { + this->chunk.get().reserve(this->chunk_size); + this->refill_chunk(); } Iterator& operator++() { - this->refill_group(); + this->refill_chunk(); return *this; } @@ -96,33 +96,33 @@ class iter::impl::Grouper { } DerefVec& operator*() { - return this->group; + return this->chunk; } DerefVec* operator->() { - return &this->group; + return &this->chunk; } }; Iterator begin() { - return {std::begin(this->container), std::end(this->container), group_size}; + return {std::begin(this->container), std::end(this->container), chunk_size}; } Iterator end() { - return {std::end(this->container), std::end(this->container), group_size}; + return {std::end(this->container), std::end(this->container), chunk_size}; } }; template -iter::impl::Grouper iter::grouper( - Container&& container, std::size_t group_size) { - return {std::forward(container), group_size}; +iter::impl::Chunker iter::chunked( + Container&& container, std::size_t chunk_size) { + return {std::forward(container), chunk_size}; } template -iter::impl::Grouper> iter::grouper( - std::initializer_list il, std::size_t group_size) { - return {std::move(il), group_size}; +iter::impl::Chunker> iter::chunked( + std::initializer_list il, std::size_t chunk_size) { + return {std::move(il), chunk_size}; } #endif diff --git a/itertools.hpp b/itertools.hpp index dddbb293..104e5b77 100644 --- a/itertools.hpp +++ b/itertools.hpp @@ -13,7 +13,7 @@ #include "filter.hpp" #include "filterfalse.hpp" #include "groupby.hpp" -#include "grouper.hpp" +#include "chunked.hpp" #include "imap.hpp" #include "sliding_window.hpp" #include "permutations.hpp" diff --git a/test/SConstruct b/test/SConstruct index 350942bb..a37669b5 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -17,6 +17,7 @@ progs = Split( ''' accumulate chain + chunked combinations combinations_with_replacement compress @@ -27,7 +28,6 @@ progs = Split( filter filterfalse groupby - grouper imap permutations powerset diff --git a/test/test_grouper.cpp b/test/test_chunked.cpp similarity index 63% rename from test/test_grouper.cpp rename to test/test_chunked.cpp index bc09bc30..e77429b0 100644 --- a/test/test_grouper.cpp +++ b/test/test_chunked.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -8,14 +8,14 @@ #include "helpers.hpp" #include "catch.hpp" -using iter::grouper; +using iter::chunked; using Vec = std::vector; using ResVec = std::vector; -TEST_CASE("grouper: basic test", "[grouper]") { +TEST_CASE("chunked: basic test", "[chunked]") { Vec ns = {1,2,3,4,5,6}; ResVec results; - for (auto&& g : grouper(ns, 2)) { + for (auto&& g : chunked(ns, 2)) { results.emplace_back(std::begin(g), std::end(g)); } @@ -24,10 +24,10 @@ TEST_CASE("grouper: basic test", "[grouper]") { REQUIRE( results == rc ); } -TEST_CASE("grouper: len(iterable) % groupsize != 0", "[grouper]") { +TEST_CASE("chunked: len(iterable) % groupsize != 0", "[chunked]") { Vec ns = {1,2,3,4,5,6,7}; ResVec results; - for (auto&& g : grouper(ns, 3)) { + for (auto&& g : chunked(ns, 3)) { results.emplace_back(std::begin(g), std::end(g)); } @@ -36,9 +36,9 @@ TEST_CASE("grouper: len(iterable) % groupsize != 0", "[grouper]") { REQUIRE( results == rc ); } -TEST_CASE("grouper: iterators can be compared", "[grouper]") { +TEST_CASE("chunked: iterators can be compared", "[chunked]") { Vec ns = {1,2,3,4,5,6,7}; - auto g = grouper(ns, 3); + auto g = chunked(ns, 3); auto it = std::begin(g); REQUIRE( it == std::begin(g) ); REQUIRE_FALSE( it != std::begin(g) ); @@ -47,20 +47,20 @@ TEST_CASE("grouper: iterators can be compared", "[grouper]") { REQUIRE_FALSE( it == std::begin(g) ); } -TEST_CASE("grouper: size 0 is empty", "[grouper]") { +TEST_CASE("chunked: size 0 is empty", "[chunked]") { Vec ns{1, 2, 3}; - auto g = grouper(ns, 0); + auto g = chunked(ns, 0); REQUIRE( std::begin(g) == std::end(g) ); } -TEST_CASE("grouper: empty iterable gives empty grouper", "[grouper]") { +TEST_CASE("chunked: empty iterable gives empty chunked", "[chunked]") { Vec ns{}; - auto g = grouper(ns, 1); + auto g = chunked(ns, 1); REQUIRE( std::begin(g) == std::end(g) ); } -TEST_CASE("grouper: iterator meets requirements", "[grouper]") { +TEST_CASE("chunked: iterator meets requirements", "[chunked]") { std::string s{}; - auto c = grouper(s, 1); + auto c = chunked(s, 1); REQUIRE( itertest::IsIterator::value ); } From 1f501304bfb2ab620972745f1758df9a49546469 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 22:09:01 -0700 Subject: [PATCH 1236/1866] moves IMapper into impl { } --- imap.hpp | 125 +++++++++++++++++++++++++++---------------------------- 1 file changed, 61 insertions(+), 64 deletions(-) diff --git a/imap.hpp b/imap.hpp index c65a7035..54f82595 100644 --- a/imap.hpp +++ b/imap.hpp @@ -8,9 +8,7 @@ #include namespace iter { - namespace detail { - template struct Expander { template @@ -58,87 +56,86 @@ namespace iter { } // end detail - // Forward declarations of IMap and imap - template - class IMap; + namespace impl { + template + class IMapper; + } template - IMap imap(MapFunc, Containers&&...); + impl::IMapper imap(MapFunc, Containers&&...); +} - template - class IMap { - // The imap function is the only thing allowed to create a IMap - friend IMap imap(MapFunc, Containers&&...); +template +class iter::impl::IMapper { + // The imap function is the only thing allowed to create a IMapper + friend IMapper iter::imap(MapFunc, Containers&&...); - using ZippedType = decltype(zip(std::declval()...)); - using ZippedIterType = iterator_type; + using ZippedType = decltype(zip(std::declval()...)); + using ZippedIterType = iterator_type; - private: - MapFunc map_func; - ZippedType zipped; + private: + MapFunc map_func; + ZippedType zipped; - using IMapIterDeref = - decltype(detail::call_with_tuple(map_func, *std::begin(zipped))); + using IMapIterDeref = + decltype(detail::call_with_tuple(map_func, *std::begin(zipped))); - // Value constructor for use only in the imap function - IMap(MapFunc in_map_func, Containers&&... in_containers) - : map_func(in_map_func), - zipped(zip(std::forward(in_containers)...)) {} + IMapper(MapFunc in_map_func, Containers&&... in_containers) + : map_func(in_map_func), + zipped(zip(std::forward(in_containers)...)) {} - public: - class Iterator : public std::iterator::type> { - private: - MapFunc* map_func; - ZippedIterType zipiter; - - public: - Iterator(MapFunc& in_map_func, ZippedIterType&& in_zipiter) - : map_func(&in_map_func), zipiter(std::move(in_zipiter)) {} - - IMapIterDeref operator*() { - return detail::call_with_tuple(*this->map_func, *(this->zipiter)); - } + public: + class Iterator : public std::iterator::type> { + private: + MapFunc* map_func; + ZippedIterType zipiter; - ArrowProxy operator->() { - return {**this}; - } + public: + Iterator(MapFunc& in_map_func, ZippedIterType&& in_zipiter) + : map_func(&in_map_func), zipiter(std::move(in_zipiter)) {} - Iterator& operator++() { - ++this->zipiter; - return *this; - } + IMapIterDeref operator*() { + return detail::call_with_tuple(*this->map_func, *(this->zipiter)); + } - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } + ArrowProxy operator->() { + return {**this}; + } - bool operator!=(const Iterator& other) const { - return this->zipiter != other.zipiter; - } + Iterator& operator++() { + ++this->zipiter; + return *this; + } - bool operator==(const Iterator& other) const { - return !(*this != other); - } - }; + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } - Iterator begin() { - return {this->map_func, this->zipped.begin()}; + bool operator!=(const Iterator& other) const { + return this->zipiter != other.zipiter; } - Iterator end() { - return {this->map_func, this->zipped.end()}; + bool operator==(const Iterator& other) const { + return !(*this != other); } }; - // Helper function to instantiate a IMap - template - IMap imap( - MapFunc map_func, Containers&&... containers) { - return {map_func, std::forward(containers)...}; + Iterator begin() { + return {this->map_func, this->zipped.begin()}; } + + Iterator end() { + return {this->map_func, this->zipped.end()}; + } +}; + +template +iter::impl::IMapper iter::imap( + MapFunc map_func, Containers&&... containers) { + return {map_func, std::forward(containers)...}; } -#endif // #ifndef ITER_IMAP_H_ +#endif From 877ef601dd38b36463e2997ece427f64ce230f3a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 22:16:50 -0700 Subject: [PATCH 1237/1866] makes Permuter ctor private, moves into impl { } --- permutations.hpp | 152 ++++++++++++++++++++++++++--------------------- 1 file changed, 84 insertions(+), 68 deletions(-) diff --git a/permutations.hpp b/permutations.hpp index 772c11d7..9e970121 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -11,95 +11,111 @@ #include namespace iter { - + namespace impl { + template + class Permuter; + } template - class Permuter { - private: - Container container; + impl::Permuter permutations(Container&&); - using IndexVector = std::vector>; - using Permutable = IterIterWrapper; + template + impl::Permuter> permutations( + std::initializer_list); +} - public: - Permuter(Container&& in_container) - : container(std::forward(in_container)) {} - - class Iterator : public std::iterator { - private: - static constexpr const int COMPLETE = -1; - static bool cmp_iters(const iterator_type& lhs, - const iterator_type& rhs) noexcept { - return *lhs < *rhs; - } +template +class iter::impl::Permuter { + private: + Container container; - Permutable working_set; - int steps{}; - - public: - Iterator(iterator_type&& sub_iter, - iterator_type&& sub_end) - : steps{sub_iter != sub_end ? 0 : COMPLETE} { - // done like this instead of using vector ctor with - // two iterators because that causes a substitution - // failure when the iterator is minimal - while (sub_iter != sub_end) { - this->working_set.get().push_back(sub_iter); - ++sub_iter; - } - std::sort(std::begin(working_set.get()), std::end(working_set.get()), - cmp_iters); - } + using IndexVector = std::vector>; + using Permutable = IterIterWrapper; - Permutable& operator*() { - return this->working_set; - } + friend Permuter iter::permutations(Container&&); + template + friend Permuter> iter::permutations( + std::initializer_list); - Permutable* operator->() { - return &this->working_set; - } + Permuter(Container&& in_container) + : container(std::forward(in_container)) {} - Iterator& operator++() { - ++this->steps; - if (!std::next_permutation(std::begin(working_set.get()), - std::end(working_set.get()), cmp_iters)) { - this->steps = COMPLETE; - } - return *this; - } + public: + class Iterator : public std::iterator { + private: + static constexpr const int COMPLETE = -1; + static bool cmp_iters(const iterator_type& lhs, + const iterator_type& rhs) noexcept { + return *lhs < *rhs; + } - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } + Permutable working_set; + int steps{}; - bool operator!=(const Iterator& other) const { - return !(*this == other); + public: + Iterator( + iterator_type&& sub_iter, iterator_type&& sub_end) + : steps{sub_iter != sub_end ? 0 : COMPLETE} { + // done like this instead of using vector ctor with + // two iterators because that causes a substitution + // failure when the iterator is minimal + while (sub_iter != sub_end) { + this->working_set.get().push_back(sub_iter); + ++sub_iter; } + std::sort(std::begin(working_set.get()), std::end(working_set.get()), + cmp_iters); + } + + Permutable& operator*() { + return this->working_set; + } - bool operator==(const Iterator& other) const { - return this->steps == other.steps; + Permutable* operator->() { + return &this->working_set; + } + + Iterator& operator++() { + ++this->steps; + if (!std::next_permutation(std::begin(working_set.get()), + std::end(working_set.get()), cmp_iters)) { + this->steps = COMPLETE; } - }; + return *this; + } - Iterator begin() { - return {std::begin(this->container), std::end(this->container)}; + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; } - Iterator end() { - return {std::end(this->container), std::end(this->container)}; + bool operator!=(const Iterator& other) const { + return !(*this == other); + } + + bool operator==(const Iterator& other) const { + return this->steps == other.steps; } }; - template - Permuter permutations(Container&& container) { - return {std::forward(container)}; + Iterator begin() { + return {std::begin(this->container), std::end(this->container)}; } - template - Permuter> permutations(std::initializer_list il) { - return {std::move(il)}; + Iterator end() { + return {std::end(this->container), std::end(this->container)}; } +}; + +template +iter::impl::Permuter iter::permutations(Container&& container) { + return {std::forward(container)}; +} + +template +iter::impl::Permuter> iter::permutations( + std::initializer_list il) { + return {std::move(il)}; } #endif From 5a6aaaa079810b12e987c45b75178fcd63150506 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 22:23:11 -0700 Subject: [PATCH 1238/1866] makes Powersetter ctor private, moves into impl {} --- powerset.hpp | 147 ++++++++++++++++++++++++++++----------------------- 1 file changed, 82 insertions(+), 65 deletions(-) diff --git a/powerset.hpp b/powerset.hpp index dda2f4fe..d69d94d5 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -12,87 +12,104 @@ #include namespace iter { + namespace impl { + template + class Powersetter; + } template - class Powersetter { - private: - Container container; - using CombinatorType = - decltype(combinations(std::declval(), 0)); + impl::Powersetter powerset(Container&&); - public: - Powersetter(Container&& in_container) - : container(std::forward(in_container)) {} - - class Iterator - : public std::iterator { - private: - typename std::remove_reference::type* container_p; - std::size_t set_size; - std::shared_ptr comb; - iterator_type comb_iter; - iterator_type comb_end; - - public: - Iterator(Container& in_container, std::size_t sz) - : container_p{&in_container}, - set_size{sz}, - comb{new CombinatorType(combinations(in_container, sz))}, - comb_iter{std::begin(*comb)}, - comb_end{std::end(*comb)} {} - - Iterator& operator++() { - ++this->comb_iter; - if (this->comb_iter == this->comb_end) { - ++this->set_size; - this->comb.reset(new CombinatorType( - combinations(*this->container_p, this->set_size))); - this->comb_iter = std::begin(*this->comb); - this->comb_end = std::end(*this->comb); - } - return *this; - } + template + impl::Powersetter> powerset( + std::initializer_list); +} - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } +template +class iter::impl::Powersetter { + private: + Container container; + using CombinatorType = decltype(combinations(std::declval(), 0)); - iterator_deref operator*() { - return *this->comb_iter; - } + friend Powersetter iter::powerset(Container&&); + template + friend Powersetter> iter::powerset( + std::initializer_list); - iterator_arrow operator->() { - apply_arrow(this->comb_iter); - } + Powersetter(Container&& in_container) + : container(std::forward(in_container)) {} - bool operator!=(const Iterator& other) const { - return !(*this == other); - } + public: + class Iterator + : public std::iterator { + private: + typename std::remove_reference::type* container_p; + std::size_t set_size; + std::shared_ptr comb; + iterator_type comb_iter; + iterator_type comb_end; - bool operator==(const Iterator& other) const { - return this->set_size == other.set_size - && this->comb_iter == other.comb_iter; + public: + Iterator(Container& in_container, std::size_t sz) + : container_p{&in_container}, + set_size{sz}, + comb{new CombinatorType(combinations(in_container, sz))}, + comb_iter{std::begin(*comb)}, + comb_end{std::end(*comb)} {} + + Iterator& operator++() { + ++this->comb_iter; + if (this->comb_iter == this->comb_end) { + ++this->set_size; + this->comb.reset(new CombinatorType( + combinations(*this->container_p, this->set_size))); + this->comb_iter = std::begin(*this->comb); + this->comb_end = std::end(*this->comb); } - }; + return *this; + } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + iterator_deref operator*() { + return *this->comb_iter; + } + + iterator_arrow operator->() { + apply_arrow(this->comb_iter); + } - Iterator begin() { - return {this->container, 0}; + bool operator!=(const Iterator& other) const { + return !(*this == other); } - Iterator end() { - return {this->container, dumb_size(this->container) + 1}; + bool operator==(const Iterator& other) const { + return this->set_size == other.set_size + && this->comb_iter == other.comb_iter; } }; - template - Powersetter powerset(Container&& container) { - return {std::forward(container)}; + Iterator begin() { + return {this->container, 0}; } - template - Powersetter> powerset(std::initializer_list il) { - return {std::move(il)}; + Iterator end() { + return {this->container, dumb_size(this->container) + 1}; } +}; + +template +iter::impl::Powersetter iter::powerset(Container&& container) { + return {std::forward(container)}; } + +template +iter::impl::Powersetter> iter::powerset( + std::initializer_list il) { + return {std::move(il)}; +} + #endif From b0595940a6c0f217c8223fa5d6f25044dc3e0f1e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 22:32:06 -0700 Subject: [PATCH 1239/1866] moves Productor into impl { } --- product.hpp | 219 +++++++++++++++++++++++++++------------------------- 1 file changed, 113 insertions(+), 106 deletions(-) diff --git a/product.hpp b/product.hpp index 77f01e33..c8b41a64 100644 --- a/product.hpp +++ b/product.hpp @@ -9,151 +9,158 @@ #include namespace iter { - template - class Productor; + namespace impl { + template + class Productor; - template - Productor product(Containers&&...); + template + class Productor; - // specialization for at least 1 template argument - template - class Productor { - static_assert(!std::is_rvalue_reference::value, - "Itertools cannot be templated with rvalue references"); + template <> + class Productor<>; + } - friend Productor product( - Container&&, RestContainers&&...); + template + impl::Productor product(Containers&&...); +} - template - friend class Productor; +// specialization for at least 1 template argument +template +class iter::impl::Productor { + static_assert(!std::is_rvalue_reference::value, + "Itertools cannot be templated with rvalue references"); - using ProdIterDeref = std::tuple, - iterator_deref...>; + friend Productor iter::product( + Container&&, RestContainers&&...); - private: - Container container; - Productor rest_products; - Productor(Container&& in_container, RestContainers&&... rest) - : container(std::forward(in_container)), - rest_products{std::forward(rest)...} {} + template + friend class Productor; - public: - class Iterator - : public std::iterator { - private: - using RestIter = typename Productor::Iterator; + using ProdIterDeref = + std::tuple, iterator_deref...>; - iterator_type iter; - iterator_type begin; + private: + Container container; + Productor rest_products; + Productor(Container&& in_container, RestContainers&&... rest) + : container(std::forward(in_container)), + rest_products{std::forward(rest)...} {} - RestIter rest_iter; - RestIter rest_end; + public: + class Iterator + : public std::iterator { + private: + using RestIter = typename Productor::Iterator; - public: - constexpr static const bool is_base_iter = false; - Iterator(const iterator_type& it, RestIter&& rest, - RestIter&& in_rest_end) - : iter{it}, begin{it}, rest_iter{rest}, rest_end{in_rest_end} {} + iterator_type iter; + iterator_type begin; - void reset() { - this->iter = this->begin; - } + RestIter rest_iter; + RestIter rest_end; - Iterator& operator++() { - ++this->rest_iter; - if (!(this->rest_iter != this->rest_end)) { - this->rest_iter.reset(); - ++this->iter; - } - return *this; - } + public: + constexpr static const bool is_base_iter = false; + Iterator(const iterator_type& it, RestIter&& rest, + RestIter&& in_rest_end) + : iter{it}, begin{it}, rest_iter{rest}, rest_end{in_rest_end} {} - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } + void reset() { + this->iter = this->begin; + } - bool operator!=(const Iterator& other) const { - return this->iter != other.iter - && (RestIter::is_base_iter - || this->rest_iter != other.rest_iter); + Iterator& operator++() { + ++this->rest_iter; + if (!(this->rest_iter != this->rest_end)) { + this->rest_iter.reset(); + ++this->iter; } + return *this; + } - bool operator==(const Iterator& other) const { - return !(*this != other); - } + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } - ProdIterDeref operator*() { - return std::tuple_cat( - std::tuple>{*this->iter}, - *this->rest_iter); - } + bool operator!=(const Iterator& other) const { + return this->iter != other.iter + && (RestIter::is_base_iter || this->rest_iter != other.rest_iter); + } - ArrowProxy operator->() { - return {**this}; - } - }; + bool operator==(const Iterator& other) const { + return !(*this != other); + } - Iterator begin() { - return {std::begin(this->container), std::begin(this->rest_products), - std::end(this->rest_products)}; + ProdIterDeref operator*() { + return std::tuple_cat( + std::tuple>{*this->iter}, *this->rest_iter); } - Iterator end() { - return {std::end(this->container), std::end(this->rest_products), - std::end(this->rest_products)}; + ArrowProxy operator->() { + return {**this}; } }; - template <> - class Productor<> { - public: - class Iterator - : public std::iterator> { - public: - constexpr static const bool is_base_iter = true; + Iterator begin() { + return {std::begin(this->container), std::begin(this->rest_products), + std::end(this->rest_products)}; + } - void reset() {} + Iterator end() { + return {std::end(this->container), std::end(this->rest_products), + std::end(this->rest_products)}; + } +}; - Iterator& operator++() { - return *this; - } +template <> +class iter::impl::Productor<> { + public: + class Iterator : public std::iterator> { + public: + constexpr static const bool is_base_iter = true; - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } + void reset() {} - // see note in zip about base case operator!= - bool operator!=(const Iterator&) const { - return false; - } + Iterator& operator++() { + return *this; + } - bool operator==(const Iterator& other) const { - return !(*this != other); - } + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } - std::tuple<> operator*() const { - return {}; - } - }; + // see note in zip about base case operator!= + bool operator!=(const Iterator&) const { + return false; + } - Iterator begin() { - return {}; + bool operator==(const Iterator& other) const { + return !(*this != other); } - Iterator end() { + std::tuple<> operator*() const { return {}; } }; - template - Productor product(Containers&&... containers) { - return {std::forward(containers)...}; + Iterator begin() { + return {}; } + Iterator end() { + return {}; + } +}; + +template +iter::impl::Productor iter::product(Containers&&... containers) { + return {std::forward(containers)...}; +} + +namespace iter { constexpr std::array, 1> product() { return {{}}; } From 0a067822cb2098ab38325784bc857ad6974bf1df Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 22:40:51 -0700 Subject: [PATCH 1240/1866] moves Range into impl { } --- range.hpp | 384 +++++++++++++++++++++++++++--------------------------- 1 file changed, 195 insertions(+), 189 deletions(-) diff --git a/range.hpp b/range.hpp index fb955e02..90465250 100644 --- a/range.hpp +++ b/range.hpp @@ -9,238 +9,244 @@ #include namespace iter { + namespace impl { + template + class Range; + } - template ::value> - class RangeIterData; - - // everything except floats template - class RangeIterData { - private: - T value_{}; - T step_{}; - - public: - constexpr RangeIterData() noexcept = default; - constexpr RangeIterData(T in_value, T in_step) noexcept : value_{in_value}, - step_{in_step} {} + constexpr impl::Range range(T) noexcept; + template + constexpr impl::Range range(T, T) noexcept; + template + constexpr impl::Range range(T, T, T) noexcept; +} - constexpr T value() const noexcept { - return this->value_; - } +namespace iter { + namespace detail { + template ::value> + class RangeIterData; - constexpr T step() const noexcept { - return this->step_; - } + // everything except floats + template + class RangeIterData { + private: + T value_{}; + T step_{}; - void inc() noexcept { - this->value_ += step_; - } + public: + constexpr RangeIterData() noexcept = default; + constexpr RangeIterData(T in_value, T in_step) noexcept + : value_{in_value}, + step_{in_step} {} - constexpr bool operator==(const RangeIterData& other) const noexcept { - return this->value_ == other.value_; - } + constexpr T value() const noexcept { + return this->value_; + } - constexpr bool operator!=(const RangeIterData& other) const noexcept { - return !(*this == other); - } - }; + constexpr T step() const noexcept { + return this->step_; + } - // float data - template - class RangeIterData { - private: - T start_{}; - T value_{}; - T step_{}; - unsigned long steps_taken{}; + void inc() noexcept { + this->value_ += step_; + } - public: - constexpr RangeIterData() noexcept = default; - constexpr RangeIterData(T in_start, T in_step) noexcept : start_{in_start}, - value_{in_start}, - step_{in_step} {} + constexpr bool operator==(const RangeIterData& other) const noexcept { + return this->value_ == other.value_; + } - constexpr T value() const noexcept { - return this->value_; - } + constexpr bool operator!=(const RangeIterData& other) const noexcept { + return !(*this == other); + } + }; - constexpr T step() const noexcept { - return this->step_; - } + // float data + template + class RangeIterData { + private: + T start_{}; + T value_{}; + T step_{}; + unsigned long steps_taken{}; - void inc() noexcept { - ++this->steps_taken; - value_ = this->start_ + (this->step_ * this->steps_taken); - } + public: + constexpr RangeIterData() noexcept = default; + constexpr RangeIterData(T in_start, T in_step) noexcept + : start_{in_start}, + value_{in_start}, + step_{in_step} {} + + constexpr T value() const noexcept { + return this->value_; + } - constexpr bool operator==(const RangeIterData& other) const noexcept { - // if the difference between the two values is less than the - // step size, they are considered equal - return (this->value_ < other.value_ ? other.value_ - this->value_ - : this->value_ - other.value_) - < this->step_; - } + constexpr T step() const noexcept { + return this->step_; + } - constexpr bool operator!=(const RangeIterData& other) const noexcept { - return !(*this == other); - } - }; + void inc() noexcept { + ++this->steps_taken; + value_ = this->start_ + (this->step_ * this->steps_taken); + } - template - class Range; + constexpr bool operator==(const RangeIterData& other) const noexcept { + // if the difference between the two values is less than the + // step size, they are considered equal + return (this->value_ < other.value_ ? other.value_ - this->value_ + : this->value_ - other.value_) + < this->step_; + } - template - constexpr Range range(T) noexcept; - template - constexpr Range range(T, T) noexcept; - template - constexpr Range range(T, T, T) noexcept; + constexpr bool operator!=(const RangeIterData& other) const noexcept { + return !(*this == other); + } + }; + } +} - // General version for everything not a float - template - class Range { - friend Range range(T); - friend Range range(T, T); - friend Range range(T, T, T); +template +class iter::impl::Range { + friend Range iter::range(T); + friend Range iter::range(T, T); + friend Range iter::range(T, T, T); - private: - const T start; - const T stop; - const T step; + private: + const T start; + const T stop; + const T step; - constexpr Range(T in_stop) noexcept : start{0}, stop{in_stop}, step{1} {} + constexpr Range(T in_stop) noexcept : start{0}, stop{in_stop}, step{1} {} - constexpr Range(T in_start, T in_stop, T in_step = 1) noexcept - : start{in_start}, - stop{in_stop}, - step{in_step} {} + constexpr Range(T in_start, T in_stop, T in_step = 1) noexcept + : start{in_start}, + stop{in_stop}, + step{in_step} {} - public: - // the reference type here is T, which doesn't strictly follow all - // of the rules, but std::vector::iterator::reference isn't - // a reference type either, this isn't any worse + public: + // the reference type here is T, which doesn't strictly follow all + // of the rules, but std::vector::iterator::reference isn't + // a reference type either, this isn't any worse - class Iterator : public std::iterator { - private: - RangeIterData data; - bool is_end; - - // compare unsigned values - static bool not_equal_to_impl(const Iterator& iter, - const Iterator& end_iter, std::true_type) noexcept { - assert(!iter.is_end); - assert(end_iter.is_end); - return iter.data.value() < end_iter.data.value(); - } + class Iterator : public std::iterator { + private: + detail::RangeIterData data; + bool is_end; + + // compare unsigned values + static bool not_equal_to_impl(const Iterator& iter, + const Iterator& end_iter, std::true_type) noexcept { + assert(!iter.is_end); + assert(end_iter.is_end); + return iter.data.value() < end_iter.data.value(); + } - // compare signed values - static bool not_equal_to_impl(const Iterator& iter, - const Iterator& end_iter, std::false_type) noexcept { - assert(!iter.is_end); - assert(end_iter.is_end); - return !(iter.data.step() > 0 - && iter.data.value() >= end_iter.data.value()) - && !(iter.data.step() < 0 - && iter.data.value() <= end_iter.data.value()); - } + // compare signed values + static bool not_equal_to_impl(const Iterator& iter, + const Iterator& end_iter, std::false_type) noexcept { + assert(!iter.is_end); + assert(end_iter.is_end); + return !(iter.data.step() > 0 + && iter.data.value() >= end_iter.data.value()) + && !(iter.data.step() < 0 + && iter.data.value() <= end_iter.data.value()); + } - static bool not_equal_to_end( - const Iterator& lhs, const Iterator& rhs) noexcept { - if (rhs.is_end) { - return not_equal_to_impl(lhs, rhs, std::is_unsigned{}); - } else { - return not_equal_to_impl(rhs, lhs, std::is_unsigned{}); - } + static bool not_equal_to_end( + const Iterator& lhs, const Iterator& rhs) noexcept { + if (rhs.is_end) { + return not_equal_to_impl(lhs, rhs, std::is_unsigned{}); + } else { + return not_equal_to_impl(rhs, lhs, std::is_unsigned{}); } + } - public: - constexpr Iterator() noexcept = default; + public: + constexpr Iterator() noexcept = default; - constexpr Iterator(T in_value, T in_step, bool in_is_end) noexcept - : data(in_value, in_step), - is_end{in_is_end} {} + constexpr Iterator(T in_value, T in_step, bool in_is_end) noexcept + : data(in_value, in_step), + is_end{in_is_end} {} - constexpr T operator*() const noexcept { - return this->data.value(); - } + constexpr T operator*() const noexcept { + return this->data.value(); + } - constexpr ArrowProxy operator->() const noexcept { - return {**this}; - } + constexpr ArrowProxy operator->() const noexcept { + return {**this}; + } - Iterator& operator++() noexcept { - this->data.inc(); - return *this; - } + Iterator& operator++() noexcept { + this->data.inc(); + return *this; + } - Iterator operator++(int) noexcept { - auto ret = *this; - ++*this; - return ret; - } + Iterator operator++(int) noexcept { + auto ret = *this; + ++*this; + return ret; + } - // This operator would more accurately read as "in bounds" - // or "incomplete" because exact comparison with the end - // isn't good enough for the purposes of this Iterator. - // There are two odd cases that need to be handled - // - // 1) The Range is infinite, such as - // Range (-1, 0, -1) which would go forever down toward - // infinitely (theoretically). If this occurs, the Range - // will instead effectively be empty - // - // 2) (stop - start) % step != 0. For - // example Range(1, 10, 2). The iterator will never be - // exactly equal to the stop value. - // - // Another way to think about it is that the "end" - // iterator represents the range of values that are invalid - // So, if an iterator is not equal to that, it is valid - // - // Two end iterators will compare equal - // - // Two non-end iterators will compare by their stored values - bool operator!=(const Iterator& other) const noexcept { - if (this->is_end && other.is_end) { - return false; - } - - if (!this->is_end && !other.is_end) { - return this->data != other.data; - } - return not_equal_to_end(*this, other); + // This operator would more accurately read as "in bounds" + // or "incomplete" because exact comparison with the end + // isn't good enough for the purposes of this Iterator. + // There are two odd cases that need to be handled + // + // 1) The Range is infinite, such as + // Range (-1, 0, -1) which would go forever down toward + // infinitely (theoretically). If this occurs, the Range + // will instead effectively be empty + // + // 2) (stop - start) % step != 0. For + // example Range(1, 10, 2). The iterator will never be + // exactly equal to the stop value. + // + // Another way to think about it is that the "end" + // iterator represents the range of values that are invalid + // So, if an iterator is not equal to that, it is valid + // + // Two end iterators will compare equal + // + // Two non-end iterators will compare by their stored values + bool operator!=(const Iterator& other) const noexcept { + if (this->is_end && other.is_end) { + return false; } - bool operator==(const Iterator& other) const noexcept { - return !(*this != other); + if (!this->is_end && !other.is_end) { + return this->data != other.data; } - }; - - constexpr Iterator begin() const noexcept { - return {start, step, false}; + return not_equal_to_end(*this, other); } - constexpr Iterator end() const noexcept { - return {stop, step, true}; + bool operator==(const Iterator& other) const noexcept { + return !(*this != other); } }; - template - constexpr Range range(T stop) noexcept { - return {stop}; + constexpr Iterator begin() const noexcept { + return {start, step, false}; } - template - constexpr Range range(T start, T stop) noexcept { - return {start, stop}; + constexpr Iterator end() const noexcept { + return {stop, step, true}; } +}; - template - constexpr Range range(T start, T stop, T step) noexcept { - return step == T(0) ? Range{0} : Range{start, stop, step}; - } +template +constexpr iter::impl::Range iter::range(T stop) noexcept { + return {stop}; +} + +template +constexpr iter::impl::Range iter::range(T start, T stop) noexcept { + return {start, stop}; +} + +template +constexpr iter::impl::Range iter::range(T start, T stop, T step) noexcept { + return step == T(0) ? impl::Range{0} : impl::Range{start, stop, step}; } -#endif // #ifndef ITER_RANGE_H_ +#endif From 2c3d34b52b1eb2c2dc67ea312d6764d72533cfd9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 22:44:00 -0700 Subject: [PATCH 1241/1866] moves Repeater[WithCount] into impl { } --- range.hpp | 2 +- repeat.hpp | 202 +++++++++++++++++++++++++++-------------------------- 2 files changed, 104 insertions(+), 100 deletions(-) diff --git a/range.hpp b/range.hpp index 90465250..0262c7ed 100644 --- a/range.hpp +++ b/range.hpp @@ -131,7 +131,7 @@ class iter::impl::Range { class Iterator : public std::iterator { private: - detail::RangeIterData data; + detail::RangeIterData data; bool is_end; // compare unsigned values diff --git a/repeat.hpp b/repeat.hpp index b2ba8ff7..bf65c2bd 100644 --- a/repeat.hpp +++ b/repeat.hpp @@ -6,140 +6,144 @@ #include namespace iter { - template - class RepeaterWithCount; + namespace impl { + template + class RepeaterWithCount; + } template - constexpr RepeaterWithCount repeat(T&&, int); + constexpr impl::RepeaterWithCount repeat(T&&, int); +} - template - class RepeaterWithCount { - friend RepeaterWithCount repeat(T&&, int); +template +class iter::impl::RepeaterWithCount { + friend RepeaterWithCount iter::repeat(T&&, int); + + private: + T elem; + int count; + constexpr RepeaterWithCount(T e, int c) + : elem(std::forward(e)), count{c} {} + + using TPlain = typename std::remove_reference::type; + + public: + class Iterator : public std::iterator { private: - T elem; + const TPlain* elem; int count; - constexpr RepeaterWithCount(T e, int c) - : elem(std::forward(e)), count{c} {} + public: + constexpr Iterator(const TPlain* e, int c) : elem{e}, count{c} {} - using TPlain = typename std::remove_reference::type; + Iterator& operator++() { + --this->count; + return *this; + } - public: - class Iterator - : public std::iterator { - private: - const TPlain* elem; - int count; - - public: - constexpr Iterator(const TPlain* e, int c) : elem{e}, count{c} {} - - Iterator& operator++() { - --this->count; - return *this; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - constexpr bool operator!=(const Iterator& other) const { - return !(*this == other); - } - - constexpr bool operator==(const Iterator& other) const { - return this->count == other.count; - } - - constexpr const TPlain& operator*() const { - return *this->elem; - } - - constexpr const TPlain* operator->() const { - return this->elem; - } - }; - - constexpr Iterator begin() { - return {&this->elem, this->count}; + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; } - constexpr Iterator end() { - return {&this->elem, 0}; + constexpr bool operator!=(const Iterator& other) const { + return !(*this == other); + } + + constexpr bool operator==(const Iterator& other) const { + return this->count == other.count; + } + + constexpr const TPlain& operator*() const { + return *this->elem; + } + + constexpr const TPlain* operator->() const { + return this->elem; } }; - template - constexpr RepeaterWithCount repeat(T&& e, int count) { - return {std::forward(e), count < 0 ? 0 : count}; + constexpr Iterator begin() { + return {&this->elem, this->count}; } - template - class Repeater; + constexpr Iterator end() { + return {&this->elem, 0}; + } +}; - template - constexpr Repeater repeat(T&&); +template +constexpr iter::impl::RepeaterWithCount iter::repeat(T&& e, int count) { + return {std::forward(e), count < 0 ? 0 : count}; +} - template - class Repeater { - friend Repeater repeat(T&&); +namespace iter { + namespace impl { + template + class Repeater; + } - private: - using TPlain = typename std::remove_reference::type; - T elem; + template + constexpr impl::Repeater repeat(T&&); +} - constexpr Repeater(T e) : elem(std::forward(e)) {} +template +class iter::impl::Repeater { + friend Repeater iter::repeat(T&&); - public: - class Iterator - : public std::iterator { - private: - const TPlain* elem; + private: + using TPlain = typename std::remove_reference::type; + T elem; - public: - constexpr Iterator(const TPlain* e) : elem{e} {} + constexpr Repeater(T e) : elem(std::forward(e)) {} - constexpr const Iterator& operator++() const { - return *this; - } + public: + class Iterator : public std::iterator { + private: + const TPlain* elem; - constexpr Iterator operator++(int) const { - return *this; - } + public: + constexpr Iterator(const TPlain* e) : elem{e} {} - constexpr bool operator!=(const Iterator&) const { - return true; - } + constexpr const Iterator& operator++() const { + return *this; + } - constexpr bool operator==(const Iterator&) const { - return false; - } + constexpr Iterator operator++(int) const { + return *this; + } - constexpr const TPlain& operator*() const { - return *this->elem; - } + constexpr bool operator!=(const Iterator&) const { + return true; + } - constexpr const TPlain* operator->() const { - return this->elem; - } - }; + constexpr bool operator==(const Iterator&) const { + return false; + } - constexpr Iterator begin() { - return {&this->elem}; + constexpr const TPlain& operator*() const { + return *this->elem; } - constexpr Iterator end() { - return {nullptr}; + constexpr const TPlain* operator->() const { + return this->elem; } }; - template - constexpr Repeater repeat(T&& e) { - return {std::forward(e)}; + constexpr Iterator begin() { + return {&this->elem}; + } + + constexpr Iterator end() { + return {nullptr}; } +}; + +template +constexpr iter::impl::Repeater iter::repeat(T&& e) { + return {std::forward(e)}; } #endif From bbdbd6fbc955477ae325363ef71eb0bcd5f026cf Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 22:51:43 -0700 Subject: [PATCH 1242/1866] moves Reverser into impl { } --- reversed.hpp | 222 ++++++++++++++++++++++++++------------------------- 1 file changed, 113 insertions(+), 109 deletions(-) diff --git a/reversed.hpp b/reversed.hpp index ccc63470..711890de 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -7,138 +7,142 @@ #include namespace iter { - template - class Reverser; + namespace impl { + template + class Reverser; - template - Reverser reversed(Container&&); + template + class Reverser; + } template - class Reverser { - private: - Container container; - friend Reverser reversed(Container&&); + impl::Reverser reversed(Container&&); - Reverser(Container&& in_container) - : container(std::forward(in_container)) {} + template + impl::Reverser reversed(T(&)[N]); +} + +template +class iter::impl::Reverser { + private: + Container container; + friend Reverser iter::reversed(Container&&); + + Reverser(Container&& in_container) + : container(std::forward(in_container)) {} + + public: + class Iterator : public std::iterator> { + private: + reverse_iterator_type sub_iter; public: - class Iterator : public std::iterator> { - private: - reverse_iterator_type sub_iter; - - public: - Iterator(reverse_iterator_type&& iter) - : sub_iter{std::move(iter)} {} - - reverse_iterator_deref operator*() { - return *this->sub_iter; - } - - reverse_iterator_arrow operator->() { - return apply_arrow(this->sub_iter); - } - - 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->container.rbegin()}; + Iterator(reverse_iterator_type&& iter) + : sub_iter{std::move(iter)} {} + + reverse_iterator_deref operator*() { + return *this->sub_iter; } - Iterator end() { - return {this->container.rend()}; + reverse_iterator_arrow operator->() { + return apply_arrow(this->sub_iter); + } + + 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); } }; - template - Reverser reversed(Container&& container) { - return {std::forward(container)}; + Iterator begin() { + return {this->container.rbegin()}; } - // - // specialization for statically allocated arrays - // - template - Reverser reversed(T(&)[N]); + Iterator end() { + return {this->container.rend()}; + } +}; - template - class Reverser { - private: - T* array; - friend Reverser reversed(T(&)[N]); +template +iter::impl::Reverser iter::reversed(Container&& container) { + return {std::forward(container)}; +} + +// specialization for statically allocated arrays + +template +class iter::impl::Reverser { + private: + T* array; + friend Reverser iter::reversed(T(&)[N]); - // Value constructor for use only in the reversed function - Reverser(T* in_array) : array{in_array} {} + // 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: - Reverser(const Reverser&) = default; - class Iterator : public std::iterator { - private: - T* sub_iter; - - public: - Iterator(T* iter) : sub_iter{iter} {} - - T& operator*() { - return *(this->sub_iter - 1); - } - - T* 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(T* iter) : sub_iter{iter} {} + + T& operator*() { + return *(this->sub_iter - 1); + } + + T* operator->() { + return (this->sub_iter - 1); } - Iterator end() { - return {this->array}; + 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); } }; - template - Reverser reversed(T(&array)[N]) { - return {array}; + Iterator begin() { + return {this->array + N}; } + + Iterator end() { + return {this->array}; + } +}; + +template +iter::impl::Reverser iter::reversed(T(&array)[N]) { + return {array}; } #endif From 91e1bad0a8e61a51dd3131a9c9dd44d2181cf2fd Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 22:54:12 -0700 Subject: [PATCH 1243/1866] moves Sliced into impl { } --- slice.hpp | 194 +++++++++++++++++++++++++++--------------------------- 1 file changed, 97 insertions(+), 97 deletions(-) diff --git a/slice.hpp b/slice.hpp index 671e3a68..703a3305 100644 --- a/slice.hpp +++ b/slice.hpp @@ -8,139 +8,139 @@ #include namespace iter { + namespace impl { + template + class Sliced; + } template - class Slice; - - template - Slice slice(Container&& container, + impl::Sliced slice(Container&& container, DifferenceType start, DifferenceType stop, DifferenceType step = 1); template - Slice slice( + impl::Sliced slice( Container&& container, DifferenceType stop); template - Slice, DifferenceType> slice( + impl::Sliced, DifferenceType> slice( std::initializer_list il, DifferenceType start, DifferenceType stop, DifferenceType step = 1); template - Slice, DifferenceType> slice( + impl::Sliced, DifferenceType> slice( std::initializer_list il, DifferenceType stop); +} - template - class Slice { +template +class iter::impl::Sliced { + private: + Container container; + DifferenceType start; + DifferenceType stop; + DifferenceType step; + + friend Sliced iter::slice( + Container&&, DifferenceType, DifferenceType, DifferenceType); + + friend Sliced iter::slice( + Container&&, DifferenceType); + + Sliced(Container&& in_container, DifferenceType in_start, + DifferenceType in_stop, DifferenceType in_step) + : container(std::forward(in_container)), + start{in_start < in_stop && in_step > 0 ? in_start : in_stop}, + stop{in_stop}, + step{in_step} {} + + public: + class Iterator : public std::iterator> { private: - Container container; - DifferenceType start; + iterator_type sub_iter; + iterator_type sub_end; + DifferenceType current; DifferenceType stop; DifferenceType step; - friend Slice slice( - Container&&, DifferenceType, DifferenceType, DifferenceType); - - friend Slice slice(Container&&, DifferenceType); - - Slice(Container&& in_container, DifferenceType in_start, - DifferenceType in_stop, DifferenceType in_step) - : container(std::forward(in_container)), - start{in_start < in_stop && in_step > 0 ? in_start : in_stop}, + public: + Iterator(iterator_type&& si, iterator_type&& se, + DifferenceType in_start, DifferenceType in_stop, DifferenceType in_step) + : sub_iter{std::move(si)}, + sub_end{std::move(se)}, + current{in_start}, stop{in_stop}, step{in_step} {} - public: - class Iterator : public std::iterator> { - private: - iterator_type sub_iter; - iterator_type sub_end; - DifferenceType current; - DifferenceType stop; - DifferenceType step; - - public: - Iterator(iterator_type&& si, iterator_type&& se, - DifferenceType in_start, DifferenceType in_stop, - DifferenceType in_step) - : sub_iter{std::move(si)}, - sub_end{std::move(se)}, - current{in_start}, - stop{in_stop}, - step{in_step} {} - - iterator_deref operator*() { - return *this->sub_iter; - } - - iterator_arrow operator->() { - return apply_arrow(this->sub_iter); - } - - Iterator& operator++() { - dumb_advance(this->sub_iter, this->sub_end, this->step); - this->current += this->step; - if (this->stop < this->current) { - this->current = this->stop; - } - return *this; - } + iterator_deref operator*() { + return *this->sub_iter; + } - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } + iterator_arrow operator->() { + return apply_arrow(this->sub_iter); + } - bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter - && this->current != other.current; + Iterator& operator++() { + dumb_advance(this->sub_iter, this->sub_end, this->step); + this->current += this->step; + if (this->stop < this->current) { + this->current = this->stop; } + return *this; + } - bool operator==(const Iterator& other) const { - return !(*this != other); - } - }; + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } - Iterator begin() { - auto it = std::begin(this->container); - dumb_advance(it, std::end(this->container), this->start); - return {std::move(it), std::end(this->container), this->start, this->stop, - this->step}; + bool operator!=(const Iterator& other) const { + return this->sub_iter != other.sub_iter && this->current != other.current; } - Iterator end() { - return {std::end(this->container), std::end(this->container), this->stop, - this->stop, this->step}; + bool operator==(const Iterator& other) const { + return !(*this != other); } }; - // Helper function to instantiate a Slice - template - Slice slice(Container&& container, - DifferenceType start, DifferenceType stop, DifferenceType step) { - return {std::forward(container), start, stop, step}; + Iterator begin() { + auto it = std::begin(this->container); + dumb_advance(it, std::end(this->container), this->start); + return {std::move(it), std::end(this->container), this->start, this->stop, + this->step}; } - // only give the end as an arg and assume step is 1 and begin is 0 - template - Slice slice( - Container&& container, DifferenceType stop) { - return {std::forward(container), 0, stop, 1}; + Iterator end() { + return {std::end(this->container), std::end(this->container), this->stop, + this->stop, this->step}; } +}; - template - Slice, DifferenceType> slice( - std::initializer_list il, DifferenceType start, DifferenceType stop, - DifferenceType step) { - return {std::move(il), start, stop, step}; - } +// Helper function to instantiate a Sliced +template +iter::impl::Sliced iter::slice(Container&& container, + DifferenceType start, DifferenceType stop, DifferenceType step) { + return {std::forward(container), start, stop, step}; +} - template - Slice, DifferenceType> slice( - std::initializer_list il, DifferenceType stop) { - return {std::move(il), 0, stop, 1}; - } +// only give the end as an arg and assume step is 1 and begin is 0 +template +iter::impl::Sliced iter::slice( + Container&& container, DifferenceType stop) { + return {std::forward(container), 0, stop, 1}; +} + +template +iter::impl::Sliced, DifferenceType> iter::slice( + std::initializer_list il, DifferenceType start, DifferenceType stop, + DifferenceType step) { + return {std::move(il), start, stop, step}; +} + +template +iter::impl::Sliced, DifferenceType> iter::slice( + std::initializer_list il, DifferenceType stop) { + return {std::move(il), 0, stop, 1}; } #endif From 1ffd05c77e441e820cf6b9e1bd48626b5a100529 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 22:56:16 -0700 Subject: [PATCH 1244/1866] moves WindowSlider into impl { } --- sliding_window.hpp | 149 +++++++++++++++++++++++---------------------- 1 file changed, 75 insertions(+), 74 deletions(-) diff --git a/sliding_window.hpp b/sliding_window.hpp index aefbca30..75fb0bf4 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -9,106 +9,107 @@ #include namespace iter { - template - class SlidingWindow; + namespace impl { + template + class WindowSlider; + } template - SlidingWindow sliding_window(Container&&, std::size_t); + impl::WindowSlider sliding_window(Container&&, std::size_t); template - SlidingWindow> sliding_window( + impl::WindowSlider> sliding_window( std::initializer_list, std::size_t); +} - template - class SlidingWindow { - private: - Container container; - std::size_t window_size; +template +class iter::impl::WindowSlider { + private: + Container container; + std::size_t window_size; - friend SlidingWindow sliding_window(Container&&, std::size_t); + friend WindowSlider iter::sliding_window(Container&&, std::size_t); - template - friend SlidingWindow> sliding_window( - std::initializer_list, std::size_t); + template + friend WindowSlider> iter::sliding_window( + std::initializer_list, std::size_t); - SlidingWindow(Container&& in_container, std::size_t win_sz) - : container(std::forward(in_container)), - window_size{win_sz} {} + WindowSlider(Container&& in_container, std::size_t win_sz) + : container(std::forward(in_container)), window_size{win_sz} {} - using IndexVector = std::deque>; - using DerefVec = IterIterWrapper; + using IndexVector = std::deque>; + using DerefVec = IterIterWrapper; - public: - class Iterator : public std::iterator { - private: - iterator_type sub_iter; - DerefVec window; - - public: - Iterator(iterator_type&& in_iter, - const iterator_type& in_end, std::size_t window_sz) - : sub_iter(std::move(in_iter)) { - std::size_t i{0}; - while (i < window_sz && this->sub_iter != in_end) { - this->window.get().push_back(this->sub_iter); - ++i; - if (i != window_sz) ++this->sub_iter; - } - } - - bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter; - } + public: + class Iterator : public std::iterator { + private: + iterator_type sub_iter; + DerefVec window; - bool operator==(const Iterator& other) const { - return !(*this != other); + public: + Iterator(iterator_type&& in_iter, + const iterator_type& in_end, std::size_t window_sz) + : sub_iter(std::move(in_iter)) { + std::size_t i{0}; + while (i < window_sz && this->sub_iter != in_end) { + this->window.get().push_back(this->sub_iter); + ++i; + if (i != window_sz) ++this->sub_iter; } + } - DerefVec& operator*() { - return this->window; - } + bool operator!=(const Iterator& other) const { + return this->sub_iter != other.sub_iter; + } - DerefVec* operator->() { - return this->window; - } + bool operator==(const Iterator& other) const { + return !(*this != other); + } - Iterator& operator++() { - ++this->sub_iter; - this->window.get().pop_front(); - this->window.get().push_back(this->sub_iter); - return *this; - } + DerefVec& operator*() { + return this->window; + } - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - }; + DerefVec* operator->() { + return this->window; + } - Iterator begin() { - return {(this->window_size != 0 ? std::begin(this->container) - : std::end(this->container)), - std::end(this->container), this->window_size}; + Iterator& operator++() { + ++this->sub_iter; + this->window.get().pop_front(); + this->window.get().push_back(this->sub_iter); + return *this; } - Iterator end() { - return {std::end(this->container), std::end(this->container), - this->window_size}; + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; } }; - template - SlidingWindow sliding_window( - Container&& container, std::size_t window_size) { - return {std::forward(container), window_size}; + Iterator begin() { + return {(this->window_size != 0 ? std::begin(this->container) + : std::end(this->container)), + std::end(this->container), this->window_size}; } - template - SlidingWindow> sliding_window( - std::initializer_list il, std::size_t window_size) { - return {std::move(il), window_size}; + Iterator end() { + return {std::end(this->container), std::end(this->container), + this->window_size}; } +}; + +template +iter::impl::WindowSlider iter::sliding_window( + Container&& container, std::size_t window_size) { + return {std::forward(container), window_size}; +} + +template +iter::impl::WindowSlider> iter::sliding_window( + std::initializer_list il, std::size_t window_size) { + return {std::move(il), window_size}; } #endif From 03ab7fd6d77a9402216dbfa94b9ef357c7d8aabb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 22:58:34 -0700 Subject: [PATCH 1245/1866] moves SortedView into impl { } --- sorted.hpp | 83 +++++++++++++++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 39 deletions(-) diff --git a/sorted.hpp b/sorted.hpp index 318ae415..27f67323 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -9,57 +9,62 @@ #include namespace iter { - template - class Sorted; + namespace impl { + template + class SortedView; + } template - Sorted sorted(Container&&, CompareFunc); - - template - class Sorted { - private: - using IterIterWrap = IterIterWrapper>>; - using ItIt = iterator_type; + impl::SortedView sorted(Container&&, CompareFunc); +} - template - friend Sorted sorted(C&&, F); +template +class iter::impl::SortedView { + private: + using IterIterWrap = IterIterWrapper>>; + using ItIt = iterator_type; - Container container; - IterIterWrap sorted_iters; + template + friend SortedView iter::sorted(C&&, F); - template - Sorted(Container&& in_container, CompareFunc compare_func) - : container(std::forward(in_container)) { - // Fill the sorted_iters vector with an iterator to each - // element in the container - for (auto iter = std::begin(this->container); - iter != std::end(this->container); ++iter) { - this->sorted_iters.get().push_back(iter); - } + Container container; + IterIterWrap sorted_iters; - // sort by comparing the elements that the iterators point to - std::sort(std::begin(sorted_iters.get()), std::end(sorted_iters.get()), - [compare_func](const iterator_type& it1, - const iterator_type& it2) { - return compare_func(*it1, *it2); - }); + template + SortedView(Container&& in_container, CompareFunc compare_func) + : container(std::forward(in_container)) { + // Fill the sorted_iters vector with an iterator to each + // element in the container + for (auto iter = std::begin(this->container); + iter != std::end(this->container); ++iter) { + this->sorted_iters.get().push_back(iter); } - public: - ItIt begin() { - return std::begin(sorted_iters); - } + // sort by comparing the elements that the iterators point to + std::sort(std::begin(sorted_iters.get()), std::end(sorted_iters.get()), + [compare_func](const iterator_type& it1, + const iterator_type& it2) { + return compare_func(*it1, *it2); + }); + } - ItIt end() { - return std::end(sorted_iters); - } - }; + public: + ItIt begin() { + return std::begin(sorted_iters); + } - template - Sorted sorted(Container&& container, CompareFunc compare_func) { - return {std::forward(container), compare_func}; + ItIt end() { + return std::end(sorted_iters); } +}; +template +iter::impl::SortedView iter::sorted( + Container&& container, CompareFunc compare_func) { + return {std::forward(container), compare_func}; +} + +namespace iter { template auto sorted(Container&& container) -> decltype(sorted(std::forward(container), From 5a4daf7f47b80775f6264bda31bcc5556fbdf715 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 23:00:55 -0700 Subject: [PATCH 1246/1866] moves Taker into impl { } --- takewhile.hpp | 174 +++++++++++++++++++++++++------------------------- 1 file changed, 87 insertions(+), 87 deletions(-) diff --git a/takewhile.hpp b/takewhile.hpp index 4f09fae7..29dd4c55 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -8,121 +8,121 @@ #include namespace iter { - - // Forward declarations of TakeWhile and takewhile - template - class TakeWhile; + namespace impl { + template + class Taker; + } template - TakeWhile takewhile(FilterFunc, Container&&); + impl::Taker takewhile(FilterFunc, Container&&); template - TakeWhile> takewhile( + impl::Taker> takewhile( FilterFunc, std::initializer_list); +} - template - class TakeWhile { - private: - Container container; - FilterFunc filter_func; +template +class iter::impl::Taker { + private: + Container container; + FilterFunc filter_func; - friend TakeWhile takewhile(FilterFunc, Container&&); + friend Taker iter::takewhile(FilterFunc, Container&&); - template - friend TakeWhile> takewhile( - FF, std::initializer_list); + template + friend Taker> iter::takewhile( + FF, std::initializer_list); - TakeWhile(FilterFunc in_filter_func, Container&& in_container) - : container(std::forward(in_container)), - filter_func(in_filter_func) {} + Taker(FilterFunc in_filter_func, Container&& in_container) + : container(std::forward(in_container)), + filter_func(in_filter_func) {} - public: - class Iterator : public std::iterator> { - private: - using Holder = DerefHolder>; - iterator_type sub_iter; - iterator_type sub_end; - Holder item; - FilterFunc* filter_func; - - void inc_sub_iter() { - ++this->sub_iter; - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); - } - } - - void check_current() { - if (this->sub_iter != this->sub_end - && !(*this->filter_func)(this->item.get())) { - this->sub_iter = this->sub_end; - } - } - - public: - Iterator(iterator_type&& iter, iterator_type&& end, - FilterFunc& in_filter_func) - : sub_iter{std::move(iter)}, - sub_end{std::move(end)}, - filter_func(&in_filter_func) { - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); - } - this->check_current(); + public: + class Iterator : public std::iterator> { + private: + using Holder = DerefHolder>; + iterator_type sub_iter; + iterator_type sub_end; + Holder item; + FilterFunc* filter_func; + + void inc_sub_iter() { + ++this->sub_iter; + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); } + } - typename Holder::reference operator*() { - return this->item.get(); + void check_current() { + if (this->sub_iter != this->sub_end + && !(*this->filter_func)(this->item.get())) { + this->sub_iter = this->sub_end; } + } - typename Holder::pointer operator->() { - return this->item.get_ptr(); + public: + Iterator(iterator_type&& iter, iterator_type&& end, + FilterFunc& in_filter_func) + : sub_iter{std::move(iter)}, + sub_end{std::move(end)}, + filter_func(&in_filter_func) { + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); } + this->check_current(); + } - Iterator& operator++() { - this->inc_sub_iter(); - this->check_current(); - return *this; - } + typename Holder::reference operator*() { + return this->item.get(); + } - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } + typename Holder::pointer operator->() { + return this->item.get_ptr(); + } - bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter; - } + Iterator& operator++() { + this->inc_sub_iter(); + this->check_current(); + return *this; + } - bool operator==(const Iterator& other) const { - return !(*this != other); - } - }; + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } - Iterator begin() { - return {std::begin(this->container), std::end(this->container), - this->filter_func}; + bool operator!=(const Iterator& other) const { + return this->sub_iter != other.sub_iter; } - Iterator end() { - return {std::end(this->container), std::end(this->container), - this->filter_func}; + bool operator==(const Iterator& other) const { + return !(*this != other); } }; - template - TakeWhile takewhile( - FilterFunc filter_func, Container&& container) { - return {filter_func, std::forward(container)}; + Iterator begin() { + return {std::begin(this->container), std::end(this->container), + this->filter_func}; } - template - TakeWhile> takewhile( - FilterFunc filter_func, std::initializer_list il) { - return {filter_func, std::move(il)}; + Iterator end() { + return {std::end(this->container), std::end(this->container), + this->filter_func}; } +}; + +template +iter::impl::Taker iter::takewhile( + FilterFunc filter_func, Container&& container) { + return {filter_func, std::forward(container)}; +} + +template +iter::impl::Taker> iter::takewhile( + FilterFunc filter_func, std::initializer_list il) { + return {filter_func, std::move(il)}; } #endif From 8cce4cb5b39dd6e0130c792ed8fcd9051f6af39c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 23:03:46 -0700 Subject: [PATCH 1247/1866] moves Zipped into impl { } --- zip.hpp | 229 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 116 insertions(+), 113 deletions(-) diff --git a/zip.hpp b/zip.hpp index 038808df..23e56221 100644 --- a/zip.hpp +++ b/zip.hpp @@ -8,140 +8,143 @@ #include namespace iter { - template - class Zipped; + namespace impl { + template + class Zipped; + + template + class Zipped; + + template <> + class Zipped<>; + } template - Zipped zip(Containers&&...); + impl::Zipped zip(Containers&&...); +} - // specialization for at least 1 template argument - template - class Zipped { - using ZipIterDeref = std::tuple, - iterator_deref...>; +// specialization for at least 1 template argument +template +class iter::impl::Zipped { + using ZipIterDeref = + std::tuple, iterator_deref...>; - friend Zipped zip( - Container&&, RestContainers&&...); + friend Zipped iter::zip( + Container&&, RestContainers&&...); - template - friend class Zipped; + template + friend class Zipped; + private: + Container container; + Zipped rest_zipped; + Zipped(Container&& in_container, RestContainers&&... rest) + : container(std::forward(in_container)), + rest_zipped{std::forward(rest)...} {} + + public: + class Iterator : public std::iterator { private: - Container container; - Zipped rest_zipped; - Zipped(Container&& in_container, RestContainers&&... rest) - : container(std::forward(in_container)), - rest_zipped{std::forward(rest)...} {} + using RestIter = typename Zipped::Iterator; + + iterator_type iter; + RestIter rest_iter; public: - class Iterator - : public std::iterator { - private: - using RestIter = typename Zipped::Iterator; - - iterator_type iter; - RestIter rest_iter; - - public: - constexpr static const bool is_base_iter = false; - Iterator(iterator_type&& it, RestIter&& rest) - : iter{std::move(it)}, rest_iter{std::move(rest)} {} - - Iterator& operator++() { - ++this->iter; - ++this->rest_iter; - return *this; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - bool operator!=(const Iterator& other) const { - return this->iter != other.iter - && (RestIter::is_base_iter - || this->rest_iter != other.rest_iter); - } - - bool operator==(const Iterator& other) const { - return !(*this != other); - } - - 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-> () -> ArrowProxy { - return {**this}; - } - }; - - Iterator begin() { - return {std::begin(this->container), std::begin(this->rest_zipped)}; + constexpr static const bool is_base_iter = false; + Iterator(iterator_type&& it, RestIter&& rest) + : iter{std::move(it)}, rest_iter{std::move(rest)} {} + + Iterator& operator++() { + ++this->iter; + ++this->rest_iter; + return *this; + } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; } - Iterator end() { - return {std::end(this->container), std::end(this->rest_zipped)}; + bool operator!=(const Iterator& other) const { + return this->iter != other.iter + && (RestIter::is_base_iter || this->rest_iter != other.rest_iter); + } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } + + 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 -> () -> ArrowProxy { + return {**this}; } }; - template <> - class Zipped<> { + Iterator begin() { + return {std::begin(this->container), std::begin(this->rest_zipped)}; + } + + Iterator end() { + return {std::end(this->container), std::end(this->rest_zipped)}; + } +}; + +template <> +class iter::impl::Zipped<> { + public: + class Iterator : public std::iterator> { public: - class Iterator - : public std::iterator> { - public: - constexpr static const bool is_base_iter = true; - - Iterator& operator++() { - return *this; - } - - Iterator operator++(int) { - 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; - } - - bool operator==(const Iterator& other) const { - return !(*this != other); - } - - std::tuple<> operator*() { - return std::tuple<>{}; - } - - auto operator-> () -> ArrowProxy { - return {**this}; - } - }; - - Iterator begin() { - return {}; + constexpr static const bool is_base_iter = true; + + Iterator& operator++() { + return *this; + } + + Iterator operator++(int) { + 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; } - Iterator end() { - return {}; + bool operator==(const Iterator& other) const { + return !(*this != other); + } + + std::tuple<> operator*() { + return std::tuple<>{}; + } + + auto operator -> () -> ArrowProxy { + return {**this}; } }; - template - Zipped zip(Containers&&... containers) { - return {std::forward(containers)...}; + Iterator begin() { + return {}; } + + Iterator end() { + return {}; + } +}; + +template +iter::impl::Zipped iter::zip(Containers&&... containers) { + return {std::forward(containers)...}; } #endif From def95a24cc85b7d0999bfb89a797e7b3ce79ab1a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 23:06:41 -0700 Subject: [PATCH 1248/1866] moves ZippedLongest into impl { } --- zip_longest.hpp | 212 +++++++++++++++++++++++++----------------------- 1 file changed, 109 insertions(+), 103 deletions(-) diff --git a/zip_longest.hpp b/zip_longest.hpp index 7029bb50..cde50074 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -9,145 +9,151 @@ #include namespace iter { + namespace impl { + template + class ZippedLongest; - template - using OptIterDeref = boost::optional>; + template + class ZippedLongest; - template - class ZippedLongest; + template <> + class ZippedLongest<>; + } template - ZippedLongest zip_longest(Containers&&...); + impl::ZippedLongest zip_longest(Containers&&...); +} + +template +class iter::impl::ZippedLongest { + static_assert(!std::is_rvalue_reference::value, + "Itertools cannot be templated with rvalue references"); + + friend ZippedLongest zip_longest( + Container&&, RestContainers&&...); + + template + friend class ZippedLongest; - template - class ZippedLongest { - static_assert(!std::is_rvalue_reference::value, - "Itertools cannot be templated with rvalue references"); + private: + template + using OptIterDeref = boost::optional>; - friend ZippedLongest zip_longest( - Container&&, RestContainers&&...); + using OptType = OptIterDeref; + using ZipIterDeref = std::tuple...>; - template - friend class ZippedLongest; + Container container; + ZippedLongest rest_zipped; + ZippedLongest(Container&& in_container, RestContainers&&... rest) + : container(std::forward(in_container)), + rest_zipped{std::forward(rest)...} {} + public: + class Iterator : public std::iterator { private: - using OptType = OptIterDeref; - using ZipIterDeref = std::tuple...>; + using RestIter = typename ZippedLongest::Iterator; - Container container; - ZippedLongest rest_zipped; - ZippedLongest(Container&& in_container, RestContainers&&... rest) - : container(std::forward(in_container)), - rest_zipped{std::forward(rest)...} {} + iterator_type iter; + iterator_type end; + RestIter rest_iter; public: - class Iterator - : public std::iterator { - private: - using RestIter = typename ZippedLongest::Iterator; - - iterator_type iter; - iterator_type end; - RestIter rest_iter; - - public: - Iterator(iterator_type&& it, iterator_type&& in_end, - RestIter&& rest) - : iter{std::move(it)}, - end{std::move(in_end)}, - rest_iter{std::move(rest)} {} - - Iterator& operator++() { - if (this->iter != this->end) { - ++this->iter; - } - ++this->rest_iter; - return *this; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; + Iterator(iterator_type&& it, iterator_type&& in_end, + RestIter&& rest) + : iter{std::move(it)}, + end{std::move(in_end)}, + rest_iter{std::move(rest)} {} + + Iterator& operator++() { + if (this->iter != this->end) { + ++this->iter; } + ++this->rest_iter; + return *this; + } - bool operator!=(const Iterator& other) const { - return this->iter != other.iter || this->rest_iter != other.rest_iter; - } + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } - bool operator==(const Iterator& other) const { - return !(*this != other); - } + bool operator!=(const Iterator& other) const { + return this->iter != other.iter || this->rest_iter != other.rest_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); - } - } + bool operator==(const Iterator& other) const { + return !(*this != other); + } - ArrowProxy operator->() { - return {**this}; + 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); } - }; - - Iterator begin() { - return {std::begin(this->container), std::end(this->container), - std::begin(this->rest_zipped)}; } - Iterator end() { - return {std::end(this->container), std::end(this->container), - std::end(this->rest_zipped)}; + ArrowProxy operator->() { + return {**this}; } }; - template <> - class ZippedLongest<> { - public: - class Iterator - : public std::iterator> { - public: - Iterator& operator++() { - return *this; - } + Iterator begin() { + return {std::begin(this->container), std::end(this->container), + std::begin(this->rest_zipped)}; + } - constexpr Iterator operator++(int) const { - return *this; - } + Iterator end() { + return {std::end(this->container), std::end(this->container), + std::end(this->rest_zipped)}; + } +}; - constexpr bool operator!=(const Iterator&) const { - return false; - } +template <> +class iter::impl::ZippedLongest<> { + public: + class Iterator : public std::iterator> { + public: + Iterator& operator++() { + return *this; + } - constexpr bool operator==(const Iterator&) const { - return true; - } + constexpr Iterator operator++(int) const { + return *this; + } - constexpr std::tuple<> operator*() const { - return {}; - } + constexpr bool operator!=(const Iterator&) const { + return false; + } - constexpr ArrowProxy> operator->() const { - return {{}}; - } - }; + constexpr bool operator==(const Iterator&) const { + return true; + } - constexpr Iterator begin() const { + constexpr std::tuple<> operator*() const { return {}; } - constexpr Iterator end() const { - return {}; + constexpr ArrowProxy> operator->() const { + return {{}}; } }; - template - ZippedLongest zip_longest(Containers&&... containers) { - return {std::forward(containers)...}; + constexpr Iterator begin() const { + return {}; + } + + constexpr Iterator end() const { + return {}; } +}; + +template +iter::impl::ZippedLongest iter::zip_longest( + Containers&&... containers) { + return {std::forward(containers)...}; } #endif From f18f822996ee01a2ab750d146e42f117b2944643 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 23:15:05 -0700 Subject: [PATCH 1249/1866] Moves all of iterbase and iteriter into impl { } It's mostly used inside of the implementation classes anyway --- accumulate.hpp | 4 +- filter.hpp | 132 ++++++++++++++++----------------- filterfalse.hpp | 6 +- groupby.hpp | 4 +- imap.hpp | 4 +- iteratoriterator.hpp | 4 +- iterbase.hpp | 2 + range.hpp | 2 +- sorted.hpp | 4 +- test/helpers.hpp | 2 +- test/test_iteratoriterator.cpp | 2 +- unique_everseen.hpp | 4 +- unique_justseen.hpp | 2 +- 13 files changed, 88 insertions(+), 84 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index c91319e8..95b464c0 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -142,11 +142,11 @@ namespace iter { auto accumulate(Container&& container) -> decltype(accumulate( std::forward(container), std::plus< - typename std::remove_reference>::type>{})) { + typename std::remove_reference>::type>{})) { return accumulate( std::forward(container), std::plus< - typename std::remove_reference>::type>{}); + typename std::remove_reference>::type>{}); } template diff --git a/filter.hpp b/filter.hpp index 9a7b203f..f31aa145 100644 --- a/filter.hpp +++ b/filter.hpp @@ -43,75 +43,75 @@ class iter::impl::Filtered { class Iterator : public std::iterator> { protected: - using Holder = DerefHolder>; - iterator_type sub_iter; - iterator_type sub_end; - Holder item; - FilterFunc* filter_func; - - void inc_sub_iter() { - ++this->sub_iter; - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); - } - } - - // increment until the iterator points to is true on the - // predicate. Called by constructor and operator++ - void skip_failures() { - while (this->sub_iter != this->sub_end - && !(*this->filter_func)(this->item.get())) { - this->inc_sub_iter(); - } - } + using Holder = DerefHolder>; + iterator_type sub_iter; + iterator_type sub_end; + Holder item; + FilterFunc* filter_func; + + void inc_sub_iter() { + ++this->sub_iter; + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); + } + } + + // increment until the iterator points to is true on the + // predicate. Called by constructor and operator++ + void skip_failures() { + while (this->sub_iter != this->sub_end + && !(*this->filter_func)(this->item.get())) { + this->inc_sub_iter(); + } + } public: - Iterator(iterator_type iter, iterator_type end, - FilterFunc& in_filter_func) - : sub_iter{iter}, sub_end{end}, filter_func(&in_filter_func) { - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); - } - this->skip_failures(); - } - - typename Holder::reference operator*() { - return this->item.get(); - } - - typename Holder::pointer operator->() { - return this->item.get_ptr(); - } - - Iterator& operator++() { - this->inc_sub_iter(); - this->skip_failures(); - 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(iterator_type iter, iterator_type end, + FilterFunc& in_filter_func) + : sub_iter{iter}, sub_end{end}, filter_func(&in_filter_func) { + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); + } + this->skip_failures(); + } + + typename Holder::reference operator*() { + return this->item.get(); + } + + typename Holder::pointer operator->() { + return this->item.get_ptr(); + } + + Iterator& operator++() { + this->inc_sub_iter(); + this->skip_failures(); + 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 {std::begin(this->container), std::end(this->container), - this->filter_func}; + this->filter_func}; } Iterator end() { return {std::end(this->container), std::end(this->container), - this->filter_func}; + this->filter_func}; } }; @@ -131,14 +131,14 @@ namespace iter { namespace detail { template - bool boolean_cast(const T& t) { - return bool(t); - } + bool boolean_cast(const T& t) { + return bool(t); + } template - class BoolTester { - public: - bool operator()(const iterator_deref item) const { + class BoolTester { + public: + bool operator()(const impl::iterator_deref item) const { return bool(item); } }; diff --git a/filterfalse.hpp b/filterfalse.hpp index 9d7d7840..850cfec4 100644 --- a/filterfalse.hpp +++ b/filterfalse.hpp @@ -25,12 +25,12 @@ namespace iter { PredicateFlipper(const PredicateFlipper&) = default; // Calls the filter_func - bool operator()(const iterator_deref item) const { + bool operator()(const impl::iterator_deref item) const { return !bool(filter_func(item)); } // with non-const incase FilterFunc::operator() is non-const - bool operator()(const iterator_deref item) { + bool operator()(const impl::iterator_deref item) { return !bool(filter_func(item)); } }; @@ -40,7 +40,7 @@ namespace iter { template class BoolFlipper { public: - bool operator()(const iterator_deref item) const { + bool operator()(const impl::iterator_deref item) const { return !bool(item); } }; diff --git a/groupby.hpp b/groupby.hpp index 8262652b..8bd6091e 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -294,8 +294,8 @@ namespace iter { template class ItemReturner { public: - iterator_deref operator()( - iterator_deref item) const { + impl::iterator_deref operator()( + impl::iterator_deref item) const { return item; } }; diff --git a/imap.hpp b/imap.hpp index 54f82595..d679a918 100644 --- a/imap.hpp +++ b/imap.hpp @@ -78,7 +78,7 @@ class iter::impl::IMapper { ZippedType zipped; using IMapIterDeref = - decltype(detail::call_with_tuple(map_func, *std::begin(zipped))); + decltype(iter::detail::call_with_tuple(map_func, *std::begin(zipped))); IMapper(MapFunc in_map_func, Containers&&... in_containers) : map_func(in_map_func), @@ -96,7 +96,7 @@ class iter::impl::IMapper { : map_func(&in_map_func), zipiter(std::move(in_zipiter)) {} IMapIterDeref operator*() { - return detail::call_with_tuple(*this->map_func, *(this->zipiter)); + return iter::detail::call_with_tuple(*this->map_func, *(this->zipiter)); } ArrowProxy operator->() { diff --git a/iteratoriterator.hpp b/iteratoriterator.hpp index ad330c6c..9752830b 100644 --- a/iteratoriterator.hpp +++ b/iteratoriterator.hpp @@ -15,6 +15,7 @@ // behave like some_collection when iterated over or indexed namespace iter { + namespace impl { template struct HasConstDeref : std::false_type {}; @@ -75,7 +76,7 @@ namespace iter { return **this->sub_iter; } - auto operator-> () -> decltype(*sub_iter) { + auto operator -> () -> decltype(*sub_iter) { return *this->sub_iter; } @@ -264,5 +265,6 @@ namespace iter { } }; } +} #endif diff --git a/iterbase.hpp b/iterbase.hpp index 20585a7a..749c478b 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -15,6 +15,7 @@ #include namespace iter { + namespace impl { template struct type_is { using type = T; @@ -278,5 +279,6 @@ namespace iter { } }; } +} #endif diff --git a/range.hpp b/range.hpp index 0262c7ed..2be9b940 100644 --- a/range.hpp +++ b/range.hpp @@ -131,7 +131,7 @@ class iter::impl::Range { class Iterator : public std::iterator { private: - detail::RangeIterData data; + iter::detail::RangeIterData data; bool is_end; // compare unsigned values diff --git a/sorted.hpp b/sorted.hpp index 27f67323..d7b56b0a 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -68,9 +68,9 @@ namespace iter { template auto sorted(Container&& container) -> decltype(sorted(std::forward(container), - std::less>())) { + std::less>())) { return sorted(std::forward(container), - std::less>()); + std::less>()); } } diff --git a/test/helpers.hpp b/test/helpers.hpp index 99cb404b..5a8c0755 100644 --- a/test/helpers.hpp +++ b/test/helpers.hpp @@ -172,7 +172,7 @@ class BasicIterable { } }; -using iter::void_t; +using iter::impl::void_t; template struct IsIterator : std::false_type { }; diff --git a/test/test_iteratoriterator.cpp b/test/test_iteratoriterator.cpp index e034cc71..ae963688 100644 --- a/test/test_iteratoriterator.cpp +++ b/test/test_iteratoriterator.cpp @@ -5,7 +5,7 @@ #include "catch.hpp" -using iter::IterIterWrapper; +using iter::impl::IterIterWrapper; TEST_CASE("Iterator over a vector of vector iterators", "[iteratoriterator]") { using std::vector; diff --git a/unique_everseen.hpp b/unique_everseen.hpp index 23b951c4..2c24adc3 100644 --- a/unique_everseen.hpp +++ b/unique_everseen.hpp @@ -15,9 +15,9 @@ namespace iter { // performance checking if it has ever been seen template auto unique_everseen(Container&& container) - -> impl::Filtered)>, + -> impl::Filtered)>, Container> { - using elem_t = iterator_deref; + using elem_t = impl::iterator_deref; std::unordered_set::type> elem_seen; std::function func = diff --git a/unique_justseen.hpp b/unique_justseen.hpp index 442e658e..eb1baacd 100644 --- a/unique_justseen.hpp +++ b/unique_justseen.hpp @@ -13,7 +13,7 @@ namespace iter { template struct GroupFrontGetter { - auto operator()(iterator_deref gb) + auto operator()(impl::iterator_deref gb) -> decltype(*std::begin(gb.second)) { return *std::begin(gb.second); } From 0d6be7da306e9da6b84c0f5532ffcb24380e227a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 23:18:11 -0700 Subject: [PATCH 1250/1866] renames grouper_examples to chunked_examples --- examples/SConstruct | 2 +- examples/{grouper_examples.cpp => chunked_examples.cpp} | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) rename examples/{grouper_examples.cpp => chunked_examples.cpp} (77%) diff --git a/examples/SConstruct b/examples/SConstruct index 9710069b..9e345c01 100644 --- a/examples/SConstruct +++ b/examples/SConstruct @@ -17,6 +17,7 @@ progs = Split( ''' accumulate chain + chunked combinatoric compress count @@ -26,7 +27,6 @@ progs = Split( filter filterfalse groupby - grouper imap range repeat diff --git a/examples/grouper_examples.cpp b/examples/chunked_examples.cpp similarity index 77% rename from examples/grouper_examples.cpp rename to examples/chunked_examples.cpp index 0ae6bb40..9c3046f5 100644 --- a/examples/grouper_examples.cpp +++ b/examples/chunked_examples.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -6,7 +6,7 @@ int main() { std::cout << "chunk size: 4\n"; std::vector v {1,2,3,4,5,6,7,8,9}; - for (auto&& sec : iter::grouper(v, 4)) { + for (auto&& sec : iter::chunked(v, 4)) { for (auto&& i : sec) { std::cout << i << " "; } @@ -14,7 +14,7 @@ int main() { } std::cout << "chunk size: 3\n"; - for (auto&& sec : iter::grouper(v,3)) { + for (auto&& sec : iter::chunked(v,3)) { for (auto&& i : sec) { std::cout << i << " "; } From 09c2d9ca1e766d0209a8680cddab70df6473783f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 20 Aug 2015 23:52:19 -0700 Subject: [PATCH 1251/1866] clarifies chunked() behavior --- README.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 26678192..9d214bbc 100644 --- a/README.md +++ b/README.md @@ -614,24 +614,28 @@ for (auto&& sec : sliding_window(v,4)) { chunked ------ -chunked is very similar to sliding window, except instead of the -section sliding by only 1 it goes the length of the full section. +chunked will yield subsequent chunkes of an iterable in blocks of a specified +size. The final chunk may be shorter than the rest if the chunk size given +does not evenly divide the length of the iterable Example usage: ```c++ vector v {1,2,3,4,5,6,7,8,9}; -for (auto&& sec : chunked(v,4)) -//each section will have 4 elements -//except the last one may be cut short -{ +for (auto&& sec : chunked(v,4)) { for (auto&& i : sec) { - cout << i << " "; - i.get() *= 2; + cout << i << ' '; } cout << '\n'; } ``` +The above prints: +``` +1 2 3 4 +5 6 7 8 +9 +``` + product ------ *Additional Requirements*: Input must have a ForwardIterator From 0f33cafb53810b95b35a02469d83f18a82575bad Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 22 Aug 2015 22:59:53 -0700 Subject: [PATCH 1252/1866] tests enumerate with a start index --- test/test_enumerate.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/test_enumerate.cpp b/test/test_enumerate.cpp index 3f315d3e..6f25b3bd 100644 --- a/test/test_enumerate.cpp +++ b/test/test_enumerate.cpp @@ -48,6 +48,14 @@ TEST_CASE("Postfix ++ enumerate", "[enumerate]") { REQUIRE( (*it).first == 1 ); } +TEST_CASE("enumerate: with starting value", "[enumerate]") { + std::string str = "hey"; + auto e = enumerate(str, 5); + Vec v(std::begin(e), std::end(e)); + Vec vc{{5, 'h'}, {6, 'e'}, {7, 'y'}}; + + REQUIRE( v == vc ); +} TEST_CASE("Modifications through enumerate affect container", "[enumerate]") { std::vector v{1, 2, 3, 4}; @@ -123,7 +131,6 @@ TEST_CASE("Doesn't move or copy elements of iterable", "[enumerate]") { } } - TEST_CASE("enumerate: iterator meets requirements", "[enumerate]") { std::string s{}; auto c = enumerate(s); From d1d7820c4357b38aaef4fe0966a06d0247d474ad Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 22 Aug 2015 23:00:06 -0700 Subject: [PATCH 1253/1866] adds two-argument enumerate() --- enumerate.hpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index f8cbc37e..a6c38227 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -16,31 +16,32 @@ namespace iter { } template - impl::Enumerable enumerate(Container&&); + impl::Enumerable enumerate(Container&&, std::size_t = 0); template impl::Enumerable> enumerate( - std::initializer_list); + std::initializer_list, std::size_t = 0); } template class iter::impl::Enumerable { private: Container container; + const std::size_t start; // The only thing allowed to directly instantiate an Enumerable is // the enumerate function - friend Enumerable iter::enumerate(Container&&); + friend Enumerable iter::enumerate(Container&&, std::size_t); template friend Enumerable> iter::enumerate( - std::initializer_list); + std::initializer_list, std::size_t); // for IterYield using BasePair = std::pair>; // Value constructor for use only in the enumerate function - Enumerable(Container&& in_container) - : container(std::forward(in_container)) {} + Enumerable(Container&& in_container, std::size_t in_start) + : container(std::forward(in_container)), start{in_start} {} public: // "yielded" by the Enumerable::Iterator. Has a .index, and a @@ -61,8 +62,8 @@ class iter::impl::Enumerable { std::size_t index; public: - Iterator(iterator_type&& si) - : sub_iter{std::move(si)}, index{0} {} + Iterator(iterator_type&& si, std::size_t start) + : sub_iter{std::move(si)}, index{start} {} IterYield operator*() { return {this->index, *this->sub_iter}; @@ -94,23 +95,24 @@ class iter::impl::Enumerable { }; Iterator begin() { - return {std::begin(this->container)}; + return {std::begin(this->container), start}; } Iterator end() { - return {std::end(this->container)}; + return {std::end(this->container), start}; } }; template -iter::impl::Enumerable iter::enumerate(Container&& container) { - return {std::forward(container)}; +iter::impl::Enumerable iter::enumerate( + Container&& container, std::size_t start) { + return {std::forward(container), start}; } template iter::impl::Enumerable> iter::enumerate( - std::initializer_list il) { - return {std::move(il)}; + std::initializer_list il, std::size_t start) { + return {std::move(il), start}; } #endif From d07d09196ce43a8361209373596f81ee76ccc705 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 22 Aug 2015 23:07:51 -0700 Subject: [PATCH 1254/1866] formatting --- accumulate.hpp | 8 +- filter.hpp | 132 ++++++------ groupby.hpp | 2 +- iteratoriterator.hpp | 493 ++++++++++++++++++++++--------------------- iterbase.hpp | 440 +++++++++++++++++++------------------- 5 files changed, 538 insertions(+), 537 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index 95b464c0..c43b0a67 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -141,12 +141,12 @@ namespace iter { template auto accumulate(Container&& container) -> decltype(accumulate( std::forward(container), - std::plus< - typename std::remove_reference>::type>{})) { + std::plus>::type>{})) { return accumulate( std::forward(container), - std::plus< - typename std::remove_reference>::type>{}); + std::plus>::type>{}); } template diff --git a/filter.hpp b/filter.hpp index f31aa145..ec79b166 100644 --- a/filter.hpp +++ b/filter.hpp @@ -43,75 +43,75 @@ class iter::impl::Filtered { class Iterator : public std::iterator> { protected: - using Holder = DerefHolder>; - iterator_type sub_iter; - iterator_type sub_end; - Holder item; - FilterFunc* filter_func; - - void inc_sub_iter() { - ++this->sub_iter; - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); - } - } - - // increment until the iterator points to is true on the - // predicate. Called by constructor and operator++ - void skip_failures() { - while (this->sub_iter != this->sub_end - && !(*this->filter_func)(this->item.get())) { - this->inc_sub_iter(); - } - } + using Holder = DerefHolder>; + iterator_type sub_iter; + iterator_type sub_end; + Holder item; + FilterFunc* filter_func; + + void inc_sub_iter() { + ++this->sub_iter; + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); + } + } + + // increment until the iterator points to is true on the + // predicate. Called by constructor and operator++ + void skip_failures() { + while (this->sub_iter != this->sub_end + && !(*this->filter_func)(this->item.get())) { + this->inc_sub_iter(); + } + } public: - Iterator(iterator_type iter, iterator_type end, - FilterFunc& in_filter_func) - : sub_iter{iter}, sub_end{end}, filter_func(&in_filter_func) { - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); - } - this->skip_failures(); - } - - typename Holder::reference operator*() { - return this->item.get(); - } - - typename Holder::pointer operator->() { - return this->item.get_ptr(); - } - - Iterator& operator++() { - this->inc_sub_iter(); - this->skip_failures(); - 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(iterator_type iter, iterator_type end, + FilterFunc& in_filter_func) + : sub_iter{iter}, sub_end{end}, filter_func(&in_filter_func) { + if (this->sub_iter != this->sub_end) { + this->item.reset(*this->sub_iter); + } + this->skip_failures(); + } + + typename Holder::reference operator*() { + return this->item.get(); + } + + typename Holder::pointer operator->() { + return this->item.get_ptr(); + } + + Iterator& operator++() { + this->inc_sub_iter(); + this->skip_failures(); + 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 {std::begin(this->container), std::end(this->container), - this->filter_func}; + this->filter_func}; } Iterator end() { return {std::end(this->container), std::end(this->container), - this->filter_func}; + this->filter_func}; } }; @@ -131,14 +131,14 @@ namespace iter { namespace detail { template - bool boolean_cast(const T& t) { - return bool(t); - } + bool boolean_cast(const T& t) { + return bool(t); + } template - class BoolTester { - public: - bool operator()(const impl::iterator_deref item) const { + class BoolTester { + public: + bool operator()(const impl::iterator_deref item) const { return bool(item); } }; diff --git a/groupby.hpp b/groupby.hpp index 8bd6091e..99f0fb74 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -294,7 +294,7 @@ namespace iter { template class ItemReturner { public: - impl::iterator_deref operator()( + impl::iterator_deref operator()( impl::iterator_deref item) const { return item; } diff --git a/iteratoriterator.hpp b/iteratoriterator.hpp index 9752830b..1a6b3f93 100644 --- a/iteratoriterator.hpp +++ b/iteratoriterator.hpp @@ -16,255 +16,256 @@ namespace iter { namespace impl { - template - struct HasConstDeref : std::false_type {}; - - template - struct HasConstDeref())>> - : std::true_type {}; - - template ::difference_type> - class IteratorIterator - : public std::iterator::value_type, Diff, - typename std::iterator_traits::pointer, - typename std::iterator_traits::reference> { - static_assert( - std::is_same::iterator_category, - std::random_access_iterator_tag>::value, - "IteratorIterator only works with random access iterators"); - - private: - Iter sub_iter; - - public: - IteratorIterator() = default; - IteratorIterator(const Iter& it) : sub_iter{it} {} - - bool operator==(const IteratorIterator& other) const { - return !(*this != other); - } - - bool operator!=(const IteratorIterator& other) const { - return this->sub_iter != other.sub_iter; - } - - IteratorIterator& operator++() { - ++this->sub_iter; - return *this; - } - - IteratorIterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - IteratorIterator& operator--() { - --this->sub_iter; - return *this; - } - - IteratorIterator operator--(int) { - auto ret = *this; - --*this; - return ret; - } - - auto operator*() -> decltype(**sub_iter) { - return **this->sub_iter; - } - - auto operator -> () -> decltype(*sub_iter) { - return *this->sub_iter; - } - - IteratorIterator& operator+=(Diff n) { - this->sub_iter += n; - return *this; - } - - IteratorIterator operator+(Diff n) const { - auto it = *this; - it += n; - return it; - } - - friend IteratorIterator operator+(Diff n, IteratorIterator it) { - it += n; - return it; - } - - IteratorIterator& operator-=(Diff n) { - this->sub_iter -= n; - return *this; - } - - IteratorIterator operator-(Diff n) const { - auto it = *this; - it -= n; - return it; - } - - friend IteratorIterator operator-(Diff n, IteratorIterator it) { - it -= n; - return it; - } - - Diff operator-(const IteratorIterator& rhs) const { - return this->sub_iter - rhs.sub_iter; - } - - auto operator[](Diff idx) -> decltype(*sub_iter[idx]) { - return *sub_iter[idx]; - } - - bool operator<(const IteratorIterator& rhs) const { - return this->sub_iter < rhs.sub_iter; - } - - bool operator>(const IteratorIterator& rhs) const { - return this->sub_iter > rhs.sub_iter; - } - - bool operator<=(const IteratorIterator& rhs) const { - return this->sub_iter <= rhs.sub_iter; - } - - bool operator>=(const IteratorIterator& rhs) const { - return this->sub_iter >= rhs.sub_iter; - } - }; - - template - class IterIterWrapper { - private: - Container container; - - using contained_iter = typename Container::value_type; - using size_type = typename Container::size_type; - using iterator = IteratorIterator; - using const_iterator = IteratorIterator; - using reverse_iterator = - IteratorIterator; - using const_reverse_iterator = - IteratorIterator; - - template - struct ConstAtTypeOrVoid : type_is {}; - - template - struct ConstAtTypeOrVoid().at(0))>> - : type_is().at(0))> {}; - - using const_at_type_or_void_t = typename ConstAtTypeOrVoid<>::type; - - template - struct ConstIndexTypeOrVoid : type_is {}; - - template - struct ConstIndexTypeOrVoid()[0])>> - : type_is()[0])> {}; - - using const_index_type_or_void_t = typename ConstIndexTypeOrVoid<>::type; - - public: - IterIterWrapper() = default; - - explicit IterIterWrapper(size_type sz) : container(sz) {} - - IterIterWrapper(size_type sz, const contained_iter& val) - : container(sz, val) {} - - auto at(size_type pos) -> decltype(*container.at(pos)) { - return *container.at(pos); - } - - auto at(size_type pos) const -> const_at_type_or_void_t { - return *container.at(pos); - } - - auto operator[](size_type pos) noexcept(noexcept(*container[pos])) - -> decltype(*container[pos]) { - return *container[pos]; - } - - auto operator[](size_type pos) const noexcept(noexcept(*container[pos])) - -> const_index_type_or_void_t { - return *container[pos]; - } - - bool empty() const noexcept { - return container.empty(); - } - - size_type size() const noexcept { - return container.size(); - } - - iterator begin() noexcept { - return {container.begin()}; - } - - iterator end() noexcept { - return {container.end()}; - } - - const_iterator begin() const noexcept { - return {container.begin()}; - } - - const_iterator end() const noexcept { - return {container.end()}; - } - - const_iterator cbegin() const noexcept { - return {container.cbegin()}; - } - - const_iterator cend() const noexcept { - return {container.cend()}; - } - - reverse_iterator rbegin() noexcept { - return {container.rbegin()}; - } - - reverse_iterator rend() noexcept { - return {container.rend()}; - } - - const_reverse_iterator rbegin() const noexcept { - return {container.rbegin()}; - } - - const_reverse_iterator rend() const noexcept { - return {container.rend()}; - } - - const_reverse_iterator crbegin() const noexcept { - return {container.rbegin()}; - } + template + struct HasConstDeref : std::false_type {}; + + template + struct HasConstDeref())>> + : std::true_type {}; + + template ::difference_type> + class IteratorIterator + : public std::iterator::value_type, Diff, + typename std::iterator_traits::pointer, + typename std::iterator_traits::reference> { + static_assert( + std::is_same::iterator_category, + std::random_access_iterator_tag>::value, + "IteratorIterator only works with random access iterators"); + + private: + Iter sub_iter; + + public: + IteratorIterator() = default; + IteratorIterator(const Iter& it) : sub_iter{it} {} + + bool operator==(const IteratorIterator& other) const { + return !(*this != other); + } + + bool operator!=(const IteratorIterator& other) const { + return this->sub_iter != other.sub_iter; + } + + IteratorIterator& operator++() { + ++this->sub_iter; + return *this; + } + + IteratorIterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + IteratorIterator& operator--() { + --this->sub_iter; + return *this; + } + + IteratorIterator operator--(int) { + auto ret = *this; + --*this; + return ret; + } + + auto operator*() -> decltype(**sub_iter) { + return **this->sub_iter; + } + + auto operator -> () -> decltype(*sub_iter) { + return *this->sub_iter; + } + + IteratorIterator& operator+=(Diff n) { + this->sub_iter += n; + return *this; + } + + IteratorIterator operator+(Diff n) const { + auto it = *this; + it += n; + return it; + } + + friend IteratorIterator operator+(Diff n, IteratorIterator it) { + it += n; + return it; + } + + IteratorIterator& operator-=(Diff n) { + this->sub_iter -= n; + return *this; + } + + IteratorIterator operator-(Diff n) const { + auto it = *this; + it -= n; + return it; + } + + friend IteratorIterator operator-(Diff n, IteratorIterator it) { + it -= n; + return it; + } + + Diff operator-(const IteratorIterator& rhs) const { + return this->sub_iter - rhs.sub_iter; + } + + auto operator[](Diff idx) -> decltype(*sub_iter[idx]) { + return *sub_iter[idx]; + } + + bool operator<(const IteratorIterator& rhs) const { + return this->sub_iter < rhs.sub_iter; + } + + bool operator>(const IteratorIterator& rhs) const { + return this->sub_iter > rhs.sub_iter; + } + + bool operator<=(const IteratorIterator& rhs) const { + return this->sub_iter <= rhs.sub_iter; + } + + bool operator>=(const IteratorIterator& rhs) const { + return this->sub_iter >= rhs.sub_iter; + } + }; + + template + class IterIterWrapper { + private: + Container container; + + using contained_iter = typename Container::value_type; + using size_type = typename Container::size_type; + using iterator = IteratorIterator; + using const_iterator = + IteratorIterator; + using reverse_iterator = + IteratorIterator; + using const_reverse_iterator = + IteratorIterator; + + template + struct ConstAtTypeOrVoid : type_is {}; + + template + struct ConstAtTypeOrVoid().at(0))>> + : type_is().at(0))> {}; + + using const_at_type_or_void_t = typename ConstAtTypeOrVoid<>::type; + + template + struct ConstIndexTypeOrVoid : type_is {}; + + template + struct ConstIndexTypeOrVoid()[0])>> + : type_is()[0])> {}; + + using const_index_type_or_void_t = typename ConstIndexTypeOrVoid<>::type; + + public: + IterIterWrapper() = default; + + explicit IterIterWrapper(size_type sz) : container(sz) {} + + IterIterWrapper(size_type sz, const contained_iter& val) + : container(sz, val) {} + + auto at(size_type pos) -> decltype(*container.at(pos)) { + return *container.at(pos); + } + + auto at(size_type pos) const -> const_at_type_or_void_t { + return *container.at(pos); + } + + auto operator[](size_type pos) noexcept(noexcept(*container[pos])) + -> decltype(*container[pos]) { + return *container[pos]; + } + + auto operator[](size_type pos) const noexcept(noexcept(*container[pos])) + -> const_index_type_or_void_t { + return *container[pos]; + } + + bool empty() const noexcept { + return container.empty(); + } + + size_type size() const noexcept { + return container.size(); + } + + iterator begin() noexcept { + return {container.begin()}; + } + + iterator end() noexcept { + return {container.end()}; + } + + const_iterator begin() const noexcept { + return {container.begin()}; + } + + const_iterator end() const noexcept { + return {container.end()}; + } + + const_iterator cbegin() const noexcept { + return {container.cbegin()}; + } + + const_iterator cend() const noexcept { + return {container.cend()}; + } + + reverse_iterator rbegin() noexcept { + return {container.rbegin()}; + } + + reverse_iterator rend() noexcept { + return {container.rend()}; + } + + const_reverse_iterator rbegin() const noexcept { + return {container.rbegin()}; + } + + const_reverse_iterator rend() const noexcept { + return {container.rend()}; + } + + const_reverse_iterator crbegin() const noexcept { + return {container.rbegin()}; + } - const_reverse_iterator crend() const noexcept { - return {container.rend()}; - } + const_reverse_iterator crend() const noexcept { + return {container.rend()}; + } - // get() exposes the underlying container. this allows the - // itertools to manipulate the iterators in the container - // and should not be depended on anywhere else. - Container& get() noexcept { - return container; - } + // get() exposes the underlying container. this allows the + // itertools to manipulate the iterators in the container + // and should not be depended on anywhere else. + Container& get() noexcept { + return container; + } - const Container& get() const noexcept { - return container; - } - }; -} + const Container& get() const noexcept { + return container; + } + }; + } } #endif diff --git a/iterbase.hpp b/iterbase.hpp index 749c478b..44b779cc 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -16,269 +16,269 @@ namespace iter { namespace impl { - template - struct type_is { - using type = T; - }; - - // gcc CWG 1558 - template - struct void_t_help { - using type = void; - }; - template - using void_t = typename void_t_help::type; - - // iterator_type is the type of C's iterator - template - using iterator_type = decltype(std::begin(std::declval())); - - // iterator_deref is the type obtained by dereferencing an iterator - // to an object of type C - template - using iterator_deref = decltype(*std::declval&>()); - - // const_iteator_deref is the type obtained through dereferencing - // a const iterator& (note: not a const_iterator). ie: the result - // of Container::iterator::operator*() const - template - using const_iterator_deref = - decltype(*std::declval&>()); - - template - using iterator_traits_deref = - typename std::remove_reference>::type; - - // iterator_type is the type of C's iterator - template - using reverse_iterator_type = decltype(std::declval().rbegin()); - - // iterator_deref is the type obtained by dereferencing an iterator - // to an object of type C - template - using reverse_iterator_deref = - decltype(*std::declval&>()); - - namespace detail { - template - struct ArrowHelper { - using type = void; - }; - template - struct ArrowHelper { - using type = T*; - constexpr type operator()(T* t) const noexcept { - return t; - } + struct type_is { + using type = T; }; - template - struct ArrowHelper().operator->())>> { - using type = decltype(std::declval().operator->()); - type operator()(T& t) const { - return t.operator->(); - } + // gcc CWG 1558 + template + struct void_t_help { + using type = void; }; + template + using void_t = typename void_t_help::type; + + // iterator_type is the type of C's iterator + template + using iterator_type = decltype(std::begin(std::declval())); + + // iterator_deref is the type obtained by dereferencing an iterator + // to an object of type C + template + using iterator_deref = decltype(*std::declval&>()); + + // const_iteator_deref is the type obtained through dereferencing + // a const iterator& (note: not a const_iterator). ie: the result + // of Container::iterator::operator*() const + template + using const_iterator_deref = + decltype(*std::declval&>()); + + template + using iterator_traits_deref = + typename std::remove_reference>::type; + + // iterator_type is the type of C's iterator + template + using reverse_iterator_type = decltype(std::declval().rbegin()); + + // iterator_deref is the type obtained by dereferencing an iterator + // to an object of type C + template + using reverse_iterator_deref = + decltype(*std::declval&>()); + + namespace detail { + template + struct ArrowHelper { + using type = void; + }; + + template + struct ArrowHelper { + using type = T*; + constexpr type operator()(T* t) const noexcept { + return t; + } + }; + + template + struct ArrowHelper().operator->())>> { + using type = decltype(std::declval().operator->()); + type operator()(T& t) const { + return t.operator->(); + } + }; + + template + using arrow = typename detail::ArrowHelper::type; + } + + // type of C::iterator::operator->, also works with pointers + // void if the iterator has no operator-> + template + using iterator_arrow = detail::arrow>; + template + using reverse_iterator_arrow = detail::arrow>; + + // applys the -> operator to an object, if the object is a pointer, + // it returns the pointer template - using arrow = typename detail::ArrowHelper::type; - } + detail::arrow apply_arrow(T& t) { + return detail::ArrowHelper{}(t); + } - // type of C::iterator::operator->, also works with pointers - // void if the iterator has no operator-> - template - using iterator_arrow = detail::arrow>; + // For iterators that have an operator* which returns a value + // they can return this type from their operator-> instead, which will + // wrap an object and allow it to be used with arrow + template + class ArrowProxy { + private: + using TPlain = typename std::remove_reference::type; + T obj; - template - using reverse_iterator_arrow = detail::arrow>; + public: + constexpr ArrowProxy(T&& in_obj) : obj(std::forward(in_obj)) {} - // applys the -> operator to an object, if the object is a pointer, - // it returns the pointer - template - detail::arrow apply_arrow(T& t) { - return detail::ArrowHelper{}(t); - } + TPlain* operator->() { + return &obj; + } + }; - // For iterators that have an operator* which returns a value - // they can return this type from their operator-> instead, which will - // wrap an object and allow it to be used with arrow - template - class ArrowProxy { - private: - using TPlain = typename std::remove_reference::type; - T obj; + template + struct is_random_access_iter : std::false_type {}; - public: - constexpr ArrowProxy(T&& in_obj) : obj(std::forward(in_obj)) {} + template + struct is_random_access_iter:: + iterator_category, + std::random_access_iterator_tag>::value, + void>::type> : std::true_type {}; - TPlain* operator->() { - return &obj; - } - }; - - template - struct is_random_access_iter : std::false_type {}; - - template - struct is_random_access_iter:: - iterator_category, - std::random_access_iterator_tag>::value, - void>::type> : std::true_type {}; - - template - using has_random_access_iter = is_random_access_iter>; - // because std::advance assumes a lot and is actually smart, I need a dumb - - // version that will work with most things - template - void dumb_advance(InputIt& iter, Distance distance = 1) { - for (Distance i(0); i < distance; ++i) { - ++iter; + template + using has_random_access_iter = is_random_access_iter>; + // because std::advance assumes a lot and is actually smart, I need a dumb + + // version that will work with most things + template + void dumb_advance(InputIt& iter, Distance distance = 1) { + for (Distance i(0); i < distance; ++i) { + ++iter; + } } - } - template - void dumb_advance_impl( - Iter& iter, const Iter& end, Distance distance, std::false_type) { - for (Distance i(0); i < distance && iter != end; ++i) { - ++iter; + template + void dumb_advance_impl( + Iter& iter, const Iter& end, Distance distance, std::false_type) { + for (Distance i(0); i < distance && iter != end; ++i) { + ++iter; + } } - } - template - void dumb_advance_impl( - Iter& iter, const Iter& end, Distance distance, std::true_type) { - if (static_cast(end - iter) < distance) { - iter = end; - } else { - iter += distance; + template + void dumb_advance_impl( + Iter& iter, const Iter& end, Distance distance, std::true_type) { + if (static_cast(end - iter) < distance) { + iter = end; + } else { + iter += distance; + } } - } - // iter will not be incremented past end - template - void dumb_advance(Iter& iter, const Iter& end, Distance distance = 1) { - dumb_advance_impl(iter, end, distance, is_random_access_iter{}); - } + // iter will not be incremented past end + template + void dumb_advance(Iter& iter, const Iter& end, Distance distance = 1) { + dumb_advance_impl(iter, end, distance, is_random_access_iter{}); + } - template - ForwardIt dumb_next(ForwardIt it, Distance distance = 1) { - dumb_advance(it, distance); - return it; - } + template + ForwardIt dumb_next(ForwardIt it, Distance distance = 1) { + dumb_advance(it, distance); + return it; + } - template - ForwardIt dumb_next( - ForwardIt it, const ForwardIt& end, Distance distance = 1) { - dumb_advance(it, end, distance); - return it; - } + template + ForwardIt dumb_next( + ForwardIt it, const ForwardIt& end, Distance distance = 1) { + dumb_advance(it, end, distance); + return it; + } - template - Distance dumb_size(Container&& container) { - Distance d{0}; - for (auto it = std::begin(container), end = std::end(container); it != end; - ++it) { - ++d; + template + Distance dumb_size(Container&& container) { + Distance d{0}; + for (auto it = std::begin(container), end = std::end(container); + it != end; ++it) { + ++d; + } + return d; } - return d; - } - template - struct are_same : std::true_type {}; + template + struct are_same : std::true_type {}; - template - struct are_same - : std::integral_constant::value && are_same::value> {}; + template + struct are_same + : std::integral_constant::value && are_same::value> {}; - // DerefHolder holds the value gotten from an iterator dereference - // if the iterate dereferences to an lvalue references, a pointer to the - // element is stored - // if it does not, a value is stored instead - // get() returns a reference to the held item - // get_ptr() returns a pointer to the held item - // reset() replaces the currently held item + // DerefHolder holds the value gotten from an iterator dereference + // if the iterate dereferences to an lvalue references, a pointer to the + // element is stored + // if it does not, a value is stored instead + // get() returns a reference to the held item + // get_ptr() returns a pointer to the held item + // reset() replaces the currently held item - template - class DerefHolder { - private: - 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; + template + class DerefHolder { + private: + 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; - std::unique_ptr item_p; + std::unique_ptr item_p; - public: - using reference = TPlain&; - using pointer = TPlain*; + public: + using reference = TPlain&; + using pointer = TPlain*; - DerefHolder() = default; + DerefHolder() = default; - DerefHolder(const DerefHolder& other) - : item_p{other.item_p ? new TPlain(*other.item_p) : nullptr} {} + DerefHolder(const DerefHolder& other) + : item_p{other.item_p ? new TPlain(*other.item_p) : nullptr} {} - DerefHolder& operator=(const DerefHolder& other) { - this->item_p.reset(other.item_p ? new TPlain(*other.item_p) : nullptr); - return *this; - } + DerefHolder& operator=(const DerefHolder& other) { + this->item_p.reset(other.item_p ? new TPlain(*other.item_p) : nullptr); + return *this; + } - DerefHolder(DerefHolder&&) = default; - DerefHolder& operator=(DerefHolder&&) = default; - ~DerefHolder() = default; + DerefHolder(DerefHolder&&) = default; + DerefHolder& operator=(DerefHolder&&) = default; + ~DerefHolder() = default; - reference get() { - return *this->item_p; - } + reference get() { + return *this->item_p; + } - pointer get_ptr() { - return this->item_p.get(); - } + pointer get_ptr() { + return this->item_p.get(); + } - void reset(T&& item) { - item_p.reset(new TPlain(std::move(item))); - } + void reset(T&& item) { + item_p.reset(new TPlain(std::move(item))); + } - explicit operator bool() const { - return this->item_p; - } - }; + explicit operator bool() const { + return this->item_p; + } + }; - // Specialization for when T is an lvalue ref. Keep this in mind - // wherever a T appears. - template - class DerefHolder::value>::type> { - public: - using reference = T; - using pointer = typename std::remove_reference::type*; + // Specialization for when T is an lvalue ref. Keep this in mind + // wherever a T appears. + template + class DerefHolder::value>::type> { + public: + using reference = T; + using pointer = typename std::remove_reference::type*; - private: - pointer item_p{}; + private: + pointer item_p{}; - public: - DerefHolder() = default; + public: + DerefHolder() = default; - reference get() { - return *this->item_p; - } + reference get() { + return *this->item_p; + } - pointer get_ptr() { - return this->item_p; - } + pointer get_ptr() { + return this->item_p; + } - void reset(T item) { - this->item_p = &item; - } + void reset(T item) { + this->item_p = &item; + } - explicit operator bool() const { - return this->item_p != nullptr; - } - }; -} + explicit operator bool() const { + return this->item_p != nullptr; + } + }; + } } #endif From aee0a31b21e3e124f04100d1b3113e5084b9c16c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 22 Aug 2015 23:17:34 -0700 Subject: [PATCH 1255/1866] moves iterbase and iteratoriterator into sub dir internal/ to keep make it less outwardly available/obvious --- accumulate.hpp | 2 +- chain.hpp | 2 +- chunked.hpp | 4 ++-- combinations.hpp | 4 ++-- combinations_with_replacement.hpp | 4 ++-- compress.hpp | 2 +- cycle.hpp | 2 +- dropwhile.hpp | 2 +- enumerate.hpp | 2 +- filter.hpp | 2 +- filterfalse.hpp | 2 +- groupby.hpp | 2 +- iteratoriterator.hpp => internal/iteratoriterator.hpp | 0 iterbase.hpp => internal/iterbase.hpp | 0 permutations.hpp | 4 ++-- powerset.hpp | 2 +- product.hpp | 2 +- range.hpp | 2 +- reversed.hpp | 2 +- slice.hpp | 2 +- sliding_window.hpp | 4 ++-- sorted.hpp | 4 ++-- takewhile.hpp | 2 +- test/helpers.hpp | 2 +- test/test_iteratoriterator.cpp | 2 +- unique_everseen.hpp | 2 +- unique_justseen.hpp | 2 +- zip.hpp | 2 +- zip_longest.hpp | 2 +- 29 files changed, 33 insertions(+), 33 deletions(-) rename iteratoriterator.hpp => internal/iteratoriterator.hpp (100%) rename iterbase.hpp => internal/iterbase.hpp (100%) diff --git a/accumulate.hpp b/accumulate.hpp index c43b0a67..8e94dee0 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -1,7 +1,7 @@ #ifndef ITER_ACCUMULATE_H_ #define ITER_ACCUMULATE_H_ -#include "iterbase.hpp" +#include "internal/iterbase.hpp" #include #include diff --git a/chain.hpp b/chain.hpp index 0e8c3343..5dbda67d 100644 --- a/chain.hpp +++ b/chain.hpp @@ -1,7 +1,7 @@ #ifndef ITER_CHAIN_HPP_ #define ITER_CHAIN_HPP_ -#include "iterbase.hpp" +#include "internal/iterbase.hpp" #include #include diff --git a/chunked.hpp b/chunked.hpp index 5b5981aa..0a1fd5fe 100644 --- a/chunked.hpp +++ b/chunked.hpp @@ -1,8 +1,8 @@ #ifndef ITER_CHUNKED_HPP_ #define ITER_CHUNKED_HPP_ -#include "iterbase.hpp" -#include "iteratoriterator.hpp" +#include "internal/iterbase.hpp" +#include "internal/iteratoriterator.hpp" #include #include diff --git a/combinations.hpp b/combinations.hpp index 83be1851..3ba5ef60 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -1,8 +1,8 @@ #ifndef ITER_COMBINATIONS_HPP_ #define ITER_COMBINATIONS_HPP_ -#include "iterbase.hpp" -#include "iteratoriterator.hpp" +#include "internal/iterbase.hpp" +#include "internal/iteratoriterator.hpp" #include #include diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index 64c139ba..c2f7f025 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -1,8 +1,8 @@ #ifndef ITER_COMBINATIONS_WITH_REPLACEMENT_HPP_ #define ITER_COMBINATIONS_WITH_REPLACEMENT_HPP_ -#include "iterbase.hpp" -#include "iteratoriterator.hpp" +#include "internal/iterbase.hpp" +#include "internal/iteratoriterator.hpp" #include #include diff --git a/compress.hpp b/compress.hpp index d6ef8096..7e19a4c5 100644 --- a/compress.hpp +++ b/compress.hpp @@ -1,7 +1,7 @@ #ifndef ITER_COMPRESS_H_ #define ITER_COMPRESS_H_ -#include "iterbase.hpp" +#include "internal/iterbase.hpp" #include #include diff --git a/cycle.hpp b/cycle.hpp index 07356032..001cf719 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -1,7 +1,7 @@ #ifndef ITER_CYCLE_H_ #define ITER_CYCLE_H_ -#include "iterbase.hpp" +#include "internal/iterbase.hpp" #include #include diff --git a/dropwhile.hpp b/dropwhile.hpp index 9efbdbc3..76975dfc 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -1,7 +1,7 @@ #ifndef ITER_DROPWHILE_H_ #define ITER_DROPWHILE_H_ -#include "iterbase.hpp" +#include "internal/iterbase.hpp" #include #include diff --git a/enumerate.hpp b/enumerate.hpp index a6c38227..ffb2a8eb 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -1,7 +1,7 @@ #ifndef ITER_ENUMERATE_H_ #define ITER_ENUMERATE_H_ -#include "iterbase.hpp" +#include "internal/iterbase.hpp" #include #include diff --git a/filter.hpp b/filter.hpp index ec79b166..381ad056 100644 --- a/filter.hpp +++ b/filter.hpp @@ -1,7 +1,7 @@ #ifndef ITER_FILTER_H_ #define ITER_FILTER_H_ -#include "iterbase.hpp" +#include "internal/iterbase.hpp" #include #include diff --git a/filterfalse.hpp b/filterfalse.hpp index 850cfec4..425893e0 100644 --- a/filterfalse.hpp +++ b/filterfalse.hpp @@ -1,7 +1,7 @@ #ifndef ITER_FILTER_FALSE_HPP_ #define ITER_FILTER_FALSE_HPP_ -#include "iterbase.hpp" +#include "internal/iterbase.hpp" #include "filter.hpp" #include diff --git a/groupby.hpp b/groupby.hpp index 99f0fb74..f02edca0 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -3,7 +3,7 @@ // this is easily the most functionally complex itertool -#include "iterbase.hpp" +#include "internal/iterbase.hpp" #include #include diff --git a/iteratoriterator.hpp b/internal/iteratoriterator.hpp similarity index 100% rename from iteratoriterator.hpp rename to internal/iteratoriterator.hpp diff --git a/iterbase.hpp b/internal/iterbase.hpp similarity index 100% rename from iterbase.hpp rename to internal/iterbase.hpp diff --git a/permutations.hpp b/permutations.hpp index 9e970121..a847956a 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -1,8 +1,8 @@ #ifndef ITER_PERMUTATIONS_HPP_ #define ITER_PERMUTATIONS_HPP_ -#include "iterbase.hpp" -#include "iteratoriterator.hpp" +#include "internal/iterbase.hpp" +#include "internal/iteratoriterator.hpp" #include #include diff --git a/powerset.hpp b/powerset.hpp index d69d94d5..c1cd96dc 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -1,7 +1,7 @@ #ifndef ITER_POWERSET_HPP_ #define ITER_POWERSET_HPP_ -#include "iterbase.hpp" +#include "internal/iterbase.hpp" #include "combinations.hpp" #include diff --git a/product.hpp b/product.hpp index c8b41a64..f83d5221 100644 --- a/product.hpp +++ b/product.hpp @@ -1,7 +1,7 @@ #ifndef ITER_PRODUCT_HPP_ #define ITER_PRODUCT_HPP_ -#include "iterbase.hpp" +#include "internal/iterbase.hpp" #include #include diff --git a/range.hpp b/range.hpp index 2be9b940..3c142da8 100644 --- a/range.hpp +++ b/range.hpp @@ -1,7 +1,7 @@ #ifndef ITER_RANGE_H_ #define ITER_RANGE_H_ -#include "iterbase.hpp" +#include "internal/iterbase.hpp" #include #include diff --git a/reversed.hpp b/reversed.hpp index 711890de..c52f1e4a 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -1,7 +1,7 @@ #ifndef ITER_REVERSE_HPP_ #define ITER_REVERSE_HPP_ -#include "iterbase.hpp" +#include "internal/iterbase.hpp" #include #include diff --git a/slice.hpp b/slice.hpp index 703a3305..e960da85 100644 --- a/slice.hpp +++ b/slice.hpp @@ -1,7 +1,7 @@ #ifndef ITER_SLICE_HPP_ #define ITER_SLICE_HPP_ -#include "iterbase.hpp" +#include "internal/iterbase.hpp" #include #include diff --git a/sliding_window.hpp b/sliding_window.hpp index 75fb0bf4..9493afe0 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -1,8 +1,8 @@ #ifndef ITER_SLIDING_WINDOW_HPP_ #define ITER_SLIDING_WINDOW_HPP_ -#include "iterbase.hpp" -#include "iteratoriterator.hpp" +#include "internal/iterbase.hpp" +#include "internal/iteratoriterator.hpp" #include #include diff --git a/sorted.hpp b/sorted.hpp index d7b56b0a..7eee9881 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -1,8 +1,8 @@ #ifndef ITER_SORTED_HPP_ #define ITER_SORTED_HPP_ -#include "iterbase.hpp" -#include "iteratoriterator.hpp" +#include "internal/iterbase.hpp" +#include "internal/iteratoriterator.hpp" #include #include diff --git a/takewhile.hpp b/takewhile.hpp index 29dd4c55..1449d154 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -1,7 +1,7 @@ #ifndef ITER_TAKEWHILE_H_ #define ITER_TAKEWHILE_H_ -#include "iterbase.hpp" +#include "internal/iterbase.hpp" #include #include diff --git a/test/helpers.hpp b/test/helpers.hpp index 5a8c0755..1b370f89 100644 --- a/test/helpers.hpp +++ b/test/helpers.hpp @@ -1,7 +1,7 @@ #ifndef TEST_HELPER_H_ #define TEST_HELPER_H_ -#include +#include #include #include diff --git a/test/test_iteratoriterator.cpp b/test/test_iteratoriterator.cpp index ae963688..6903d8cf 100644 --- a/test/test_iteratoriterator.cpp +++ b/test/test_iteratoriterator.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/unique_everseen.hpp b/unique_everseen.hpp index 2c24adc3..5a993304 100644 --- a/unique_everseen.hpp +++ b/unique_everseen.hpp @@ -1,7 +1,7 @@ #ifndef ITER_UNIQUE_EVERSEEN_HPP_ #define ITER_UNIQUE_EVERSEEN_HPP_ -#include "iterbase.hpp" +#include "internal/iterbase.hpp" #include "filter.hpp" #include diff --git a/unique_justseen.hpp b/unique_justseen.hpp index eb1baacd..8d5c6f30 100644 --- a/unique_justseen.hpp +++ b/unique_justseen.hpp @@ -1,7 +1,7 @@ #ifndef ITER_UNIQUE_JUSTSEEN_HPP #define ITER_UNIQUE_JUSTSEEN_HPP -#include "iterbase.hpp" +#include "internal/iterbase.hpp" #include "groupby.hpp" #include "imap.hpp" diff --git a/zip.hpp b/zip.hpp index 23e56221..154cd2a7 100644 --- a/zip.hpp +++ b/zip.hpp @@ -1,7 +1,7 @@ #ifndef ITER_ZIP_HPP_ #define ITER_ZIP_HPP_ -#include "iterbase.hpp" +#include "internal/iterbase.hpp" #include #include diff --git a/zip_longest.hpp b/zip_longest.hpp index cde50074..a2321a46 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -1,7 +1,7 @@ #ifndef ITER_ZIP_LONGEST_HPP_ #define ITER_ZIP_LONGEST_HPP_ -#include "iterbase.hpp" +#include "internal/iterbase.hpp" #include #include From eb0230ad8cb09b3f82ee866c01bb941332c843c9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 22 Aug 2015 23:32:12 -0700 Subject: [PATCH 1256/1866] notes requirements on accumulate and reversed --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 9d214bbc..01ef6796 100644 --- a/README.md +++ b/README.md @@ -365,6 +365,9 @@ Thus, if the group is unsorted, the same key may appear multiple times. accumulate ------- +*Additional Requirements*: Type return from functor (with reference removed) +must be assignable. + Differs from `std::accumulate` (which in my humble opinion should be named `std::reduce` or `std::foldl`). It is similar to a functional reduce where one can see all of the intermediate results. By default, it keeps a running sum. @@ -556,6 +559,8 @@ for (auto&& i : chain.from_iterable(matrix)) { reversed ------- +*Additional Requirements*: Input must have `.rbegin()` and `.rend()`, or be +a plain C array. Iterates over elements of a sequence in reverse order. From 50f605924bf8f9ef31eb71d362a5f53d04da11df Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 22 Aug 2015 23:56:56 -0700 Subject: [PATCH 1257/1866] clarifies permutations requirement --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 01ef6796..bbc54e7d 100644 --- a/README.md +++ b/README.md @@ -696,13 +696,12 @@ for (auto&& v : combinations_with_replacement(s, 2)) { } ``` - permutations ----------- -*Additional Requirements*: Input must have a ForwardIterator +*Additional Requirements*: Input must have a ForwardIterator. Iterator must +have an `operator*() const`. -Generates all the permutations of a range using `std::next_permutation`. The -iterators of the sequence passed must have an `operator*() const` +Generates all the permutations of a range using `std::next_permutation`. Example usage: ```c++ From 39de8bff8d444caf626252d6718a42cd7f2af693 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 22 Aug 2015 23:57:07 -0700 Subject: [PATCH 1258/1866] optional default ctor in BasicIterable::Iterator --- test/helpers.hpp | 3 +++ test/test_combinations.cpp | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/test/helpers.hpp b/test/helpers.hpp index 1b370f89..06d0e035 100644 --- a/test/helpers.hpp +++ b/test/helpers.hpp @@ -148,6 +148,9 @@ class BasicIterable { private: T *p; public: +#ifdef DEFINE_DEFAULT_ITERATOR_CTOR + Iterator() = default; +#endif Iterator(T *b) : p{b} { } bool operator!=(const Iterator& other) const { return this->p != other.p; diff --git a/test/test_combinations.cpp b/test/test_combinations.cpp index b01c2224..278c6225 100644 --- a/test/test_combinations.cpp +++ b/test/test_combinations.cpp @@ -1,4 +1,7 @@ +#define DEFINE_DEFAULT_ITERATOR_CTOR #include "helpers.hpp" +#undef DEFINE_DEFAULT_ITERATOR_CTOR + #include #include @@ -57,6 +60,15 @@ TEST_CASE("combinations: size 0 gives nothing", "[combinations]") { REQUIRE( std::begin(c) == std::end(c) ); } +TEST_CASE("combinations: iterable without operator*() const", "[combinations]") +{ + BasicIterable bi{'x', 'y', 'z'}; + auto c = combinations(bi, 1); + auto it = std::begin(c); + ++it; + (*it)[0]; +} + TEST_CASE("combinations: binds to lvalues, moves rvalues", "[combinations]") { BasicIterable bi{'x', 'y', 'z'}; SECTION("binds to lvalues") { From fbb06cca540bffc860a6f9d8b0c7bc0b6ad0f4ff Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 00:04:09 -0700 Subject: [PATCH 1259/1866] describes groupby requirements --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index bbc54e7d..4d1b2611 100644 --- a/README.md +++ b/README.md @@ -341,6 +341,10 @@ for (auto&& i : count()) { groupby ------- +*Additional Requirements*: If the Input's iterator's `operator*()` returns +a reference, the reference must remain valid after the iterator is incremented. +Roughly equivalent to requiring the Input have a ForwardIterator. + Separate an iterable into groups sharing a common key. The following example creates a new group whenever a string of a different length is encountered. ```c++ From a3f7d9d7805ad21644ee0524343863b6110931c2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 00:06:49 -0700 Subject: [PATCH 1260/1866] notes unique_everseen requirements --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4d1b2611..0169a83f 100644 --- a/README.md +++ b/README.md @@ -228,6 +228,8 @@ for(auto&& i : filterfalse(vec)) { ``` unique\_everseen --------------- +*Additional Requirements*: Underlying values must be copy-constructible. + This is a filter adaptor that only generates values that have never been seen before. For this to work your object must be specialized for `std::hash`. From 57d89a543ea069a410e6617821153f9cc956ada6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 18:35:31 -0700 Subject: [PATCH 1261/1866] iteriter doesn't need to include zip.hpp --- internal/iteratoriterator.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/iteratoriterator.hpp b/internal/iteratoriterator.hpp index 1a6b3f93..6052cc68 100644 --- a/internal/iteratoriterator.hpp +++ b/internal/iteratoriterator.hpp @@ -2,7 +2,6 @@ #define ITERATOR_ITERATOR_HPP_ #include "iterbase.hpp" -#include "zip.hpp" #include #include #include From 025122607cd24096cab4ee416c5b2c42fb534207 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:14:06 -0700 Subject: [PATCH 1262/1866] makes accumulate implementation class move-only --- accumulate.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/accumulate.hpp b/accumulate.hpp index 8e94dee0..3d878c22 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -48,6 +48,8 @@ class iter::impl::Accumulator { accumulate_func(in_accumulate_func) {} public: + Accumulator(Accumulator&&) = default; + class Iterator : public std::iterator { private: iterator_type sub_iter; @@ -57,7 +59,7 @@ class iter::impl::Accumulator { public: Iterator(iterator_type&& iter, iterator_type&& end, - AccumulateFunc in_accumulate_func) + AccumulateFunc in_accumulate_fun) : sub_iter{std::move(iter)}, sub_end{std::move(end)}, accumulate_func(&in_accumulate_func), From c38f839d4069f3297228b63d5a7588100ebca23e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:14:50 -0700 Subject: [PATCH 1263/1866] makes chain impl classes move-only --- chain.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/chain.hpp b/chain.hpp index 5dbda67d..5ee3bcfa 100644 --- a/chain.hpp +++ b/chain.hpp @@ -46,6 +46,7 @@ class iter::impl::Chained { rest_chained{std::forward(rest)...} {} public: + Chained(Chained&&) = default; class Iterator : public std::iterator> { private: @@ -122,6 +123,7 @@ class iter::impl::Chained { : container(std::forward(in_container)) {} public: + Chained(Chained&&) = default; class Iterator : public std::iterator> { private: @@ -179,6 +181,7 @@ class iter::impl::ChainedFromIterable { : container(std::forward(in_container)) {} public: + ChainedFromIterable(ChainedFromIterable&&) = default; class Iterator : public std::iterator>> { private: From c5731834d070ced7a8796653eb178cbce0a02995 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:15:00 -0700 Subject: [PATCH 1264/1866] makes chunked impl class move-only --- chunked.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/chunked.hpp b/chunked.hpp index 0a1fd5fe..3ce976f4 100644 --- a/chunked.hpp +++ b/chunked.hpp @@ -44,6 +44,7 @@ class iter::impl::Chunker { using DerefVec = IterIterWrapper; public: + Chunker(Chunker&&) = default; class Iterator : public std::iterator { private: iterator_type sub_iter; From 3666238659c7dec7a533075a8a43f7e73a4a8250 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:15:11 -0700 Subject: [PATCH 1265/1866] makes combinations impl class move-only --- combinations.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/combinations.hpp b/combinations.hpp index 3ba5ef60..098fc9d0 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -41,6 +41,7 @@ class iter::impl::Combinator { using CombIteratorDeref = IterIterWrapper; public: + Combinator(Combinator&&) = default; class Iterator : public std::iterator { private: From e5e1dcdbe7ae09060da26037a2f2bb271da37b92 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:15:23 -0700 Subject: [PATCH 1266/1866] makes comb_w_repl impl class move-only --- combinations_with_replacement.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index c2f7f025..adc41665 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -44,6 +44,7 @@ class iter::impl::CombinatorWithReplacement { using CombIteratorDeref = IterIterWrapper; public: + CombinatorWithReplacement(CombinatorWithReplacement&&) = default; class Iterator : public std::iterator { private: From 7cc7d11c263bd0f24b750fc1a962b99d023bacc0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:15:37 -0700 Subject: [PATCH 1267/1866] makes compress impl class move-only --- compress.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/compress.hpp b/compress.hpp index 7e19a4c5..dd92c203 100644 --- a/compress.hpp +++ b/compress.hpp @@ -58,6 +58,7 @@ class iter::impl::Compressed { selectors(std::forward(in_selectors)) {} public: + Compressed(Compressed&&) = default; class Iterator : public std::iterator> { private: From a040b2f3ed40ecc8584c3cddf515e98b05a2ad6f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:15:45 -0700 Subject: [PATCH 1268/1866] makes cycle impl class move-only --- cycle.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/cycle.hpp b/cycle.hpp index 001cf719..ac4f5401 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -33,6 +33,7 @@ class iter::impl::Cycler { : container(std::forward(in_container)) {} public: + Cycler(Cycler&&) = default; class Iterator : public std::iterator> { private: From 9f963b5f917e61bdd260319bf5a8d1be334a69d6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:15:53 -0700 Subject: [PATCH 1269/1866] makes dropwhile impl class move-only --- dropwhile.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/dropwhile.hpp b/dropwhile.hpp index 76975dfc..f7f39e2a 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -39,6 +39,7 @@ class iter::impl::Dropper { filter_func(in_filter_func) {} public: + Dropper(Dropper&&) = default; class Iterator : public std::iterator> { private: From 688620476fce798d2be65dd401a67ad972a6c1fe Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:16:00 -0700 Subject: [PATCH 1270/1866] makes enumerate impl class move-only --- enumerate.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/enumerate.hpp b/enumerate.hpp index ffb2a8eb..715eb7b0 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -44,6 +44,8 @@ class iter::impl::Enumerable { : container(std::forward(in_container)), start{in_start} {} public: + Enumerable(Enumerable&&) = default; + // "yielded" by the Enumerable::Iterator. Has a .index, and a // .element referencing the value yielded by the subiterator class IterYield : public BasePair { From 8f9b4b6cbf7c519d0ca6fb9dd8c983a227c215a5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:16:13 -0700 Subject: [PATCH 1271/1866] makes filter impl class move-only --- filter.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/filter.hpp b/filter.hpp index 381ad056..7b50fd38 100644 --- a/filter.hpp +++ b/filter.hpp @@ -40,6 +40,8 @@ class iter::impl::Filtered { filter_func(in_filter_func) {} public: + Filtered(Filtered&&) = default; + class Iterator : public std::iterator> { protected: From 87974e2b6c820630e4397f02b0ab5137e90d8b2e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:16:19 -0700 Subject: [PATCH 1272/1866] makes groupby impl class move-only --- groupby.hpp | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index f02edca0..ca774609 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -44,11 +44,6 @@ class iter::impl::GroupProducer { key_func(in_key_func) {} public: - GroupProducer() = delete; - GroupProducer(const GroupProducer&) = delete; - GroupProducer& operator=(const GroupProducer&) = delete; - GroupProducer& operator=(GroupProducer&&) = delete; - GroupProducer(GroupProducer&&) = default; class Iterator; @@ -196,13 +191,7 @@ class iter::impl::GroupProducer { } } - // move-constructible, non-copy-constructible, - // non-assignable - Group() = delete; - Group(const Group&) = default; - Group& operator=(const Group&) = delete; - Group& operator=(Group&&) = delete; - + // move-constructible, non-copy-constructible, non-assignable Group(Group&& other) : owner{other.owner}, key{other.key}, completed{other.completed} { other.completed = true; From 0a0d9437d65a52badafea4dc44c4493433bb5665 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:16:27 -0700 Subject: [PATCH 1273/1866] makes imap impl class move-only --- imap.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/imap.hpp b/imap.hpp index d679a918..fc5a2e66 100644 --- a/imap.hpp +++ b/imap.hpp @@ -85,6 +85,8 @@ class iter::impl::IMapper { zipped(zip(std::forward(in_containers)...)) {} public: + IMapper(IMapper&&) = default; + class Iterator : public std::iterator::type> { private: From 29495d9c5c98293515c6a58ffb054323ae2dd035 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:16:38 -0700 Subject: [PATCH 1274/1866] makes permutations impl class move-only --- permutations.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/permutations.hpp b/permutations.hpp index a847956a..81fdb34f 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -40,6 +40,8 @@ class iter::impl::Permuter { : container(std::forward(in_container)) {} public: + Permuter(Permuter&&) = default; + class Iterator : public std::iterator { private: static constexpr const int COMPLETE = -1; From 09aef65967ba6b1c9a03809f70a05d2b4ebc659b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:16:52 -0700 Subject: [PATCH 1275/1866] makes powerset impl class move-only --- powerset.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/powerset.hpp b/powerset.hpp index c1cd96dc..83e7ebe4 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -39,6 +39,8 @@ class iter::impl::Powersetter { : container(std::forward(in_container)) {} public: + Powersetter(Powersetter&&) = default; + class Iterator : public std::iterator { private: From 4f9afa3f57c05919f50057b9045e98fe858b3e18 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:17:02 -0700 Subject: [PATCH 1276/1866] makes product impl class move-only --- product.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/product.hpp b/product.hpp index f83d5221..8939a28e 100644 --- a/product.hpp +++ b/product.hpp @@ -27,9 +27,6 @@ namespace iter { // specialization for at least 1 template argument template class iter::impl::Productor { - static_assert(!std::is_rvalue_reference::value, - "Itertools cannot be templated with rvalue references"); - friend Productor iter::product( Container&&, RestContainers&&...); @@ -47,6 +44,7 @@ class iter::impl::Productor { rest_products{std::forward(rest)...} {} public: + Productor(Productor&&) = default; class Iterator : public std::iterator { private: @@ -116,6 +114,7 @@ class iter::impl::Productor { template <> class iter::impl::Productor<> { public: + Productor(Productor&&) = default; class Iterator : public std::iterator> { public: constexpr static const bool is_base_iter = true; From 6fe614ae966b0748ea7a2e99a703e7b25d6a0152 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:17:14 -0700 Subject: [PATCH 1277/1866] makes reversed impl class move-only --- reversed.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/reversed.hpp b/reversed.hpp index c52f1e4a..28a19157 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -32,6 +32,7 @@ class iter::impl::Reverser { : container(std::forward(in_container)) {} public: + Reverser(Reverser&&) = default; class Iterator : public std::iterator> { private: @@ -95,7 +96,8 @@ class iter::impl::Reverser { Reverser(T* in_array) : array{in_array} {} public: - Reverser(const Reverser&) = default; + Reverser(Reverser&&) = default; + class Iterator : public std::iterator { private: T* sub_iter; From bcc27ca9345054c3b867f2498f63f345e53757aa Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:17:23 -0700 Subject: [PATCH 1278/1866] makes slice impl class move-only --- slice.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/slice.hpp b/slice.hpp index e960da85..09cdfb24 100644 --- a/slice.hpp +++ b/slice.hpp @@ -53,6 +53,7 @@ class iter::impl::Sliced { step{in_step} {} public: + Sliced(Sliced&&) = default; class Iterator : public std::iterator> { private: From cc7293d72c511c86b5f7e8b3f84bbba6326cf22a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:17:35 -0700 Subject: [PATCH 1279/1866] makes sliding_window impl class move-only --- sliding_window.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/sliding_window.hpp b/sliding_window.hpp index 9493afe0..cffc0e0f 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -41,6 +41,7 @@ class iter::impl::WindowSlider { using DerefVec = IterIterWrapper; public: + WindowSlider(WindowSlider&&) = default; class Iterator : public std::iterator { private: iterator_type sub_iter; From 5ac91a2262fd7dbb2fac685cbb29ef397d4427e6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:17:49 -0700 Subject: [PATCH 1280/1866] makes sorted impl class move-only --- sorted.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sorted.hpp b/sorted.hpp index 7eee9881..b546ce54 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -49,6 +49,8 @@ class iter::impl::SortedView { } public: + SortedView(SortedView&&) = default; + ItIt begin() { return std::begin(sorted_iters); } From 1316a38b888f7c5b8d3b874314ff43cf22e90991 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:18:06 -0700 Subject: [PATCH 1281/1866] makes takewhile impl class move-only --- takewhile.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/takewhile.hpp b/takewhile.hpp index 1449d154..6defbb17 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -38,6 +38,8 @@ class iter::impl::Taker { filter_func(in_filter_func) {} public: + Taker(Taker&&) = default; + class Iterator : public std::iterator> { private: From d13354df2de7e0d1e70d3c5b2766a778d337c1ae Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:18:16 -0700 Subject: [PATCH 1282/1866] makes zip impl class move-only --- zip.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zip.hpp b/zip.hpp index 154cd2a7..ecd9a26d 100644 --- a/zip.hpp +++ b/zip.hpp @@ -43,6 +43,7 @@ class iter::impl::Zipped { rest_zipped{std::forward(rest)...} {} public: + Zipped(Zipped&&) = default; class Iterator : public std::iterator { private: using RestIter = typename Zipped::Iterator; @@ -99,6 +100,7 @@ class iter::impl::Zipped { template <> class iter::impl::Zipped<> { public: + Zipped(Zipped&&) = default; class Iterator : public std::iterator> { public: constexpr static const bool is_base_iter = true; From 2b04905446f960c851d91573467c61b5ce89c8ec Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:18:24 -0700 Subject: [PATCH 1283/1866] makes zip_longest impl class move-only --- zip_longest.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/zip_longest.hpp b/zip_longest.hpp index a2321a46..dcd9ec59 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -26,9 +26,6 @@ namespace iter { template class iter::impl::ZippedLongest { - static_assert(!std::is_rvalue_reference::value, - "Itertools cannot be templated with rvalue references"); - friend ZippedLongest zip_longest( Container&&, RestContainers&&...); @@ -49,6 +46,7 @@ class iter::impl::ZippedLongest { rest_zipped{std::forward(rest)...} {} public: + ZippedLongest(ZippedLongest&&) = default; class Iterator : public std::iterator { private: using RestIter = typename ZippedLongest::Iterator; @@ -114,6 +112,7 @@ class iter::impl::ZippedLongest { template <> class iter::impl::ZippedLongest<> { public: + ZippedLongest(ZippedLongest&&) = default; class Iterator : public std::iterator> { public: Iterator& operator++() { From e7748a1b6f7b4323e4f2eb527b6baab5637b4899 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:18:49 -0700 Subject: [PATCH 1284/1866] makes repeat impl classes move-only --- repeat.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/repeat.hpp b/repeat.hpp index bf65c2bd..6ef077bc 100644 --- a/repeat.hpp +++ b/repeat.hpp @@ -29,6 +29,8 @@ class iter::impl::RepeaterWithCount { using TPlain = typename std::remove_reference::type; public: + RepeaterWithCount(RepeaterWithCount&&) = default; + class Iterator : public std::iterator { private: const TPlain* elem; @@ -100,6 +102,8 @@ class iter::impl::Repeater { constexpr Repeater(T e) : elem(std::forward(e)) {} public: + Repeater(Repeater&&) = default; + class Iterator : public std::iterator { private: const TPlain* elem; From 51c368cbd97ef3eddeb6d59fe5bd9818a0a4fc2f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:20:50 -0700 Subject: [PATCH 1285/1866] fixes address-of-temporary error in accumulate --- accumulate.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index 3d878c22..eca67cb1 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -59,10 +59,10 @@ class iter::impl::Accumulator { public: Iterator(iterator_type&& iter, iterator_type&& end, - AccumulateFunc in_accumulate_fun) + AccumulateFunc& in_accumulate_fun) : sub_iter{std::move(iter)}, sub_end{std::move(end)}, - accumulate_func(&in_accumulate_func), + accumulate_func(&in_accumulate_fun), // only get first value if not an end iterator acc_val{!(iter != end) ? nullptr : new AccumVal(*iter)} {} From f7776fea08c3be2ef9a655cbdd33db4da96cf79e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:22:27 -0700 Subject: [PATCH 1286/1866] adds missing noexcepts in friend decls --- range.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/range.hpp b/range.hpp index 3c142da8..83543dc0 100644 --- a/range.hpp +++ b/range.hpp @@ -107,9 +107,9 @@ namespace iter { template class iter::impl::Range { - friend Range iter::range(T); - friend Range iter::range(T, T); - friend Range iter::range(T, T, T); + friend Range iter::range(T) noexcept; + friend Range iter::range(T, T) noexcept; + friend Range iter::range(T, T, T) noexcept; private: const T start; From d9dbebd0ebb34c82732d04a4bf5651df7a977989 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 23:27:54 -0400 Subject: [PATCH 1287/1866] adds missing constexpr to friend decls --- range.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/range.hpp b/range.hpp index 83543dc0..8a4047c4 100644 --- a/range.hpp +++ b/range.hpp @@ -107,9 +107,9 @@ namespace iter { template class iter::impl::Range { - friend Range iter::range(T) noexcept; - friend Range iter::range(T, T) noexcept; - friend Range iter::range(T, T, T) noexcept; + friend constexpr Range iter::range(T) noexcept; + friend constexpr Range iter::range(T, T) noexcept; + friend constexpr Range iter::range(T, T, T) noexcept; private: const T start; From 024cd0525bc34755f63abda428294cf21319e5e7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Aug 2015 20:29:47 -0700 Subject: [PATCH 1288/1866] removes constexpr from friend decls --- range.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/range.hpp b/range.hpp index 8a4047c4..83543dc0 100644 --- a/range.hpp +++ b/range.hpp @@ -107,9 +107,9 @@ namespace iter { template class iter::impl::Range { - friend constexpr Range iter::range(T) noexcept; - friend constexpr Range iter::range(T, T) noexcept; - friend constexpr Range iter::range(T, T, T) noexcept; + friend Range iter::range(T) noexcept; + friend Range iter::range(T, T) noexcept; + friend Range iter::range(T, T, T) noexcept; private: const T start; From 4bf9faf15444348472dd6926cec2d8d2e52e4fef Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 24 Aug 2015 02:37:04 -0400 Subject: [PATCH 1289/1866] tests that iteratoriterator has correct traits --- test/test_iteratoriterator.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/test_iteratoriterator.cpp b/test/test_iteratoriterator.cpp index 6903d8cf..129ebd15 100644 --- a/test/test_iteratoriterator.cpp +++ b/test/test_iteratoriterator.cpp @@ -52,3 +52,12 @@ TEST_CASE("IteratorIterator operator->", "[iteratoriterator]") { auto it = std::begin(itritr); REQUIRE( it->size() == 8 ); } + +TEST_CASE("Iterate over a vector of string iterators", "[iteratoriterator]") { + std::string str = "hello world"; + IterIterWrapper> itritr; + auto it = std::begin(itritr); + static_assert(std::is_same::reference>::value, + "iterator is mis marked"); +} From f2ffc55db485504efc0544bd1c612aa19e2040fd Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 24 Aug 2015 02:38:24 -0400 Subject: [PATCH 1290/1866] corrects iteratoriterator traits previously all the iterator_traits were defined as per the outer iterator instead of the inner one. This surfaced when compiling with libc++ (as opposed to libstdc++) which doesn't tighter checks --- internal/iteratoriterator.hpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/internal/iteratoriterator.hpp b/internal/iteratoriterator.hpp index 6052cc68..75e79a69 100644 --- a/internal/iteratoriterator.hpp +++ b/internal/iteratoriterator.hpp @@ -22,24 +22,23 @@ namespace iter { struct HasConstDeref())>> : std::true_type {}; - template ::difference_type> + template class IteratorIterator : public std::iterator::value_type, Diff, - typename std::iterator_traits::pointer, - typename std::iterator_traits::reference> { + typename std::decay())>::type> { + using Diff = std::ptrdiff_t; static_assert( - std::is_same::iterator_category, + std::is_same::iterator_category, std::random_access_iterator_tag>::value, "IteratorIterator only works with random access iterators"); private: - Iter sub_iter; + TopIter sub_iter; public: IteratorIterator() = default; - IteratorIterator(const Iter& it) : sub_iter{it} {} + IteratorIterator(const TopIter& it) : sub_iter{it} {} bool operator==(const IteratorIterator& other) const { return !(*this != other); From dd9711786b4f7f82bddda38e4638d78acad2879f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 24 Aug 2015 02:40:15 -0400 Subject: [PATCH 1291/1866] adds missing explicit type in empty multiset --- test/test_powerset.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test_powerset.cpp b/test/test_powerset.cpp index 7da82744..3c13e09f 100644 --- a/test/test_powerset.cpp +++ b/test/test_powerset.cpp @@ -18,7 +18,8 @@ TEST_CASE("powerset: basic test, [1, 2, 3]", "[powerset]") { v.emplace(std::begin(st), std::end(st)); } - const IntPermSet vc = { {}, {1}, {2}, {3,}, {1,2}, {1,3}, {2,3}, {1,2,3} }; + const IntPermSet vc = { std::multiset{}, + {1}, {2}, {3,}, {1,2}, {1,3}, {2,3}, {1,2,3} }; REQUIRE( v == vc ); } From e78c34412660c79f7c552a3b2d73bb2ab8c63852 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 24 Aug 2015 02:40:40 -0400 Subject: [PATCH 1292/1866] replaces std::array of SolidInt with plain c array --- test/test_slice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_slice.cpp b/test/test_slice.cpp index ea6f5e13..921fab44 100644 --- a/test/test_slice.cpp +++ b/test/test_slice.cpp @@ -96,7 +96,7 @@ TEST_CASE("slice: moves rvalues and binds to lvalues", "[slice]") { TEST_CASE("slice: with iterable doesn't move or copy elems", "[slice]") { - constexpr std::array arr{{{6}, {7}, {8}}}; + constexpr itertest::SolidInt arr[] = {{6}, {7}, {8}}; for (auto&& i : slice(arr, 2)) { (void)i; } From b8cdccd83e73fd36b0aa52977e513b93b0e72a1b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 24 Aug 2015 02:42:34 -0400 Subject: [PATCH 1293/1866] marks repeat begin/end as const --- repeat.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/repeat.hpp b/repeat.hpp index 6ef077bc..45a6c8e9 100644 --- a/repeat.hpp +++ b/repeat.hpp @@ -67,11 +67,11 @@ class iter::impl::RepeaterWithCount { } }; - constexpr Iterator begin() { + constexpr Iterator begin() const { return {&this->elem, this->count}; } - constexpr Iterator end() { + constexpr Iterator end() const { return {&this->elem, 0}; } }; @@ -136,11 +136,11 @@ class iter::impl::Repeater { } }; - constexpr Iterator begin() { + constexpr Iterator begin() const { return {&this->elem}; } - constexpr Iterator end() { + constexpr Iterator end() const { return {nullptr}; } }; From a14ae7ac986ecafdb370b4bbeb64e6c30b0556c5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 24 Aug 2015 02:59:29 -0400 Subject: [PATCH 1294/1866] declares all repeat<> friends of all Repeater<> There's a gcc bug that causes it to *very explicitly* not allow declaring a constexpr friend specialization which is fixed in trunk as of right now, and will probably get released with gcc-5.1.1 http://stackoverflow.com/questions/32174186/ --- repeat.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/repeat.hpp b/repeat.hpp index 45a6c8e9..c33d40c5 100644 --- a/repeat.hpp +++ b/repeat.hpp @@ -17,7 +17,10 @@ namespace iter { template class iter::impl::RepeaterWithCount { - friend RepeaterWithCount iter::repeat(T&&, int); + // see stackoverflow.com/questions/32174186/ about why this isn't + // declaring just a specialization as friend + template + friend constexpr RepeaterWithCount iter::repeat(U&&, int); private: T elem; @@ -93,7 +96,8 @@ namespace iter { template class iter::impl::Repeater { - friend Repeater iter::repeat(T&&); + template + friend constexpr Repeater iter::repeat(U&&); private: using TPlain = typename std::remove_reference::type; From d936c2f246e8478026b3c759abfe7f4f95ba081e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 24 Aug 2015 03:12:33 -0400 Subject: [PATCH 1295/1866] makes range<> friends with all Range<>s --- range.hpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/range.hpp b/range.hpp index 83543dc0..74d6bc5d 100644 --- a/range.hpp +++ b/range.hpp @@ -107,9 +107,14 @@ namespace iter { template class iter::impl::Range { - friend Range iter::range(T) noexcept; - friend Range iter::range(T, T) noexcept; - friend Range iter::range(T, T, T) noexcept; + // see stackoverflow.com/questions/32174186 about why only specializations + // aren't marked as friend + template + friend constexpr Range iter::range(U) noexcept; + template + friend constexpr Range iter::range(U, U) noexcept; + template + friend constexpr Range iter::range(U, U, U) noexcept; private: const T start; From d3bd2b675a4bd98b93e8516f86ccd778f256f109 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 24 Aug 2015 13:18:08 -0400 Subject: [PATCH 1296/1866] remove_ref rather than decay to get value_type --- internal/iteratoriterator.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/iteratoriterator.hpp b/internal/iteratoriterator.hpp index 75e79a69..a49b4b06 100644 --- a/internal/iteratoriterator.hpp +++ b/internal/iteratoriterator.hpp @@ -25,7 +25,7 @@ namespace iter { template class IteratorIterator : public std::iterator())>::type> { using Diff = std::ptrdiff_t; static_assert( From 67abb0315fe75c6e7e1519b24985a1462f1bf420 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Mon, 24 Aug 2015 13:05:26 -0700 Subject: [PATCH 1297/1866] adds missing && in groupby examples --- examples/groupby_examples.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/examples/groupby_examples.cpp b/examples/groupby_examples.cpp index e4ae4048..7ee1ab74 100644 --- a/examples/groupby_examples.cpp +++ b/examples/groupby_examples.cpp @@ -35,17 +35,15 @@ int main() { } std::cout << '\n'; } - + std::cout << "ints grouped by their value:\n"; std::vector ivec = {5, 5, 6, 6, 19, 19, 19, 19, 69, 0, 10, 10}; - for (auto gb : iter::groupby(ivec)) { + for (auto&& gb : iter::groupby(ivec)) { std::cout << "key(" << gb.first << "): "; - for (auto s : gb.second) { + for (auto&& s : gb.second) { std::cout << s << " "; } std::cout << '\n'; } } - - From cdedf05fbd87d497a780e65a79c89c2f61536f39 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Mon, 24 Aug 2015 18:58:54 -0700 Subject: [PATCH 1298/1866] adds repeat constexpr test with literal --- test/test_repeat.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/test_repeat.cpp b/test/test_repeat.cpp index 3cb9e45f..b6e71a45 100644 --- a/test/test_repeat.cpp +++ b/test/test_repeat.cpp @@ -34,6 +34,13 @@ TEST_CASE("repeat: can be used as constexpr", "[repeat]") { constexpr auto i2 = ++i; (void)i2; } + { + constexpr static auto r = repeat('a'); + constexpr auto i = r.begin(); + //constexpr char c2 = *i; + //static_assert(c2 == 'a', "repeat value not as expected"); + } + { constexpr auto r = repeat(c, 2); constexpr auto i = r.begin(); From 7a3066e31e14e37143cbde04436ac7c72c6a9412 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Mon, 24 Aug 2015 18:59:45 -0700 Subject: [PATCH 1299/1866] uses custom forward to get c++14 functionality because c++11's std::forward isn't marked as constexpr. facepalm --- repeat.hpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/repeat.hpp b/repeat.hpp index c33d40c5..ecef3e49 100644 --- a/repeat.hpp +++ b/repeat.hpp @@ -9,6 +9,17 @@ namespace iter { namespace impl { template class RepeaterWithCount; + + // forward isn't constexpr until c++14 + template + constexpr T&& forward( typename std::remove_reference::type& t ) { + return static_cast(t); + } + + template + constexpr T&& forward( typename std::remove_reference::type&& t ) { + return static_cast(t); + } } template @@ -27,7 +38,7 @@ class iter::impl::RepeaterWithCount { int count; constexpr RepeaterWithCount(T e, int c) - : elem(std::forward(e)), count{c} {} + : elem(impl::forward(e)), count{c} {} using TPlain = typename std::remove_reference::type; @@ -81,7 +92,7 @@ class iter::impl::RepeaterWithCount { template constexpr iter::impl::RepeaterWithCount iter::repeat(T&& e, int count) { - return {std::forward(e), count < 0 ? 0 : count}; + return {impl::forward(e), count < 0 ? 0 : count}; } namespace iter { @@ -103,7 +114,7 @@ class iter::impl::Repeater { using TPlain = typename std::remove_reference::type; T elem; - constexpr Repeater(T e) : elem(std::forward(e)) {} + constexpr Repeater(T e) : elem(impl::forward(e)) {} public: Repeater(Repeater&&) = default; @@ -151,7 +162,7 @@ class iter::impl::Repeater { template constexpr iter::impl::Repeater iter::repeat(T&& e) { - return {std::forward(e)}; + return {impl::forward(e)}; } #endif From db3011e9f61d20e0a0070a43f12cf523b6ff6e80 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Mon, 24 Aug 2015 19:31:37 -0700 Subject: [PATCH 1300/1866] adjusts for weird libc++ mem_fn behavior I'm hesitant to call it a bug, but I think it is. libc++'s std::mem_fn doesn't seem to work when the member function is marked const. I can't get it to work with &std::string::size, for example. --- examples/groupby_examples.cpp | 8 +------- test/test_groupby.cpp | 4 ++-- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/examples/groupby_examples.cpp b/examples/groupby_examples.cpp index fb55a5cd..8d4a9918 100644 --- a/examples/groupby_examples.cpp +++ b/examples/groupby_examples.cpp @@ -5,14 +5,8 @@ #include #include -// fix OSX compilation -static int string_length(const std::string & str) -{ - return str.length(); -} - int main() { - auto len = string_length; + auto len = [](const std::string& str){ return str.size(); }; std::vector vec = { "hi", "ab", "ho", "abc", "def", diff --git a/test/test_groupby.cpp b/test/test_groupby.cpp index eddb2728..ad74be9d 100644 --- a/test/test_groupby.cpp +++ b/test/test_groupby.cpp @@ -47,7 +47,7 @@ TEST_CASE("groupby: works with lambda, callable, and function pointer") { } SECTION("lambda function") { - for (auto&& gb : groupby(vec, + for (auto&& gb : groupby(vec, [](const std::string& s){return s.size();})) { keys.push_back(gb.first); groups.emplace_back(std::begin(gb.second), std::end(gb.second)); @@ -201,7 +201,7 @@ TEST_CASE("groupby: copy constructed iterators behave as expected", TEST_CASE("groupby: operator-> on both iterator types", "[groupby]") { std::vector ns = {"a", "abc"}; - auto g = groupby(ns, std::mem_fn(&std::string::size)); + auto g = groupby(ns, [](const std::string& str){return str.size();}); auto it = std::begin(g); REQUIRE( it->first == 1 ); auto it2 = std::begin(it->second); From 4bc46f7d8c6e6c79931f2f81a284cd9d092f3714 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Mon, 24 Aug 2015 19:42:48 -0700 Subject: [PATCH 1301/1866] formatting --- repeat.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/repeat.hpp b/repeat.hpp index ecef3e49..b9fcd885 100644 --- a/repeat.hpp +++ b/repeat.hpp @@ -12,12 +12,12 @@ namespace iter { // forward isn't constexpr until c++14 template - constexpr T&& forward( typename std::remove_reference::type& t ) { + constexpr T&& forward(typename std::remove_reference::type& t) { return static_cast(t); } template - constexpr T&& forward( typename std::remove_reference::type&& t ) { + constexpr T&& forward(typename std::remove_reference::type&& t) { return static_cast(t); } } From 7bc27058aa5c67d87af6ccc4733245dd48b2fb0d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 24 Aug 2015 23:30:22 -0700 Subject: [PATCH 1302/1866] uncomments end of a repeat test --- test/test_repeat.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_repeat.cpp b/test/test_repeat.cpp index b6e71a45..ee7c03e4 100644 --- a/test/test_repeat.cpp +++ b/test/test_repeat.cpp @@ -37,8 +37,8 @@ TEST_CASE("repeat: can be used as constexpr", "[repeat]") { { constexpr static auto r = repeat('a'); constexpr auto i = r.begin(); - //constexpr char c2 = *i; - //static_assert(c2 == 'a', "repeat value not as expected"); + constexpr char c2 = *i; + static_assert(c2 == 'a', "repeat value not as expected"); } { From 56d96e6b5da6780ee0c7592fb7bb57fc0c087b49 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 24 Aug 2015 23:37:35 -0700 Subject: [PATCH 1303/1866] Notes implementation class limitations --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 0169a83f..b293c690 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,12 @@ This library takes every effort to rely on as little as possible from the underlying iterables, but if anything noteworthy is needed it is described in this document. +#### Guarantees of implementations +By implementations I mean the objects returned by the API's functions. All of +the implementation classes are move-constructible, not copy-constructible, +not assignable. All iterators that work over another iterable are tagged +as InputIterators and behave as such. + #### Feedback If you find anything not working as you expect, not compiling when you believe it should, a divergence from the python itertools behavior, or any sort of From 7886ba4e0fccdcb3f118adef8bdcde95a11c6795 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 27 Aug 2015 08:32:41 -0700 Subject: [PATCH 1304/1866] changes Group move ctor to work with gcc-4.8 If this were a big change I wouldn't do it, but all it needs is changing a{b} to a(b) in one spot, so why not. --- groupby.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/groupby.hpp b/groupby.hpp index ca774609..d794d70d 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -193,7 +193,7 @@ class iter::impl::GroupProducer { // move-constructible, non-copy-constructible, non-assignable Group(Group&& other) - : owner{other.owner}, key{other.key}, completed{other.completed} { + : owner(other.owner), key{other.key}, completed{other.completed} { other.completed = true; } From 7db884170dd8d88b431bc1209ae85fe936334029 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 27 Aug 2015 08:43:13 -0700 Subject: [PATCH 1305/1866] Removes new-gcc specific flag from SConstructs and informs that catch.hpp might be there, but CXX might be wrong --- examples/SConstruct | 3 +-- test/SConstruct | 5 +++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/SConstruct b/examples/SConstruct index 9e345c01..8040c840 100644 --- a/examples/SConstruct +++ b/examples/SConstruct @@ -1,11 +1,10 @@ import os env = Environment( - ENV = {'PATH' : os.environ['PATH']}, + ENV=os.environ, CXX='c++', CXXFLAGS= ['-g', '-Wall', '-Wextra', '-pedantic', '-std=c++11', - '-fdiagnostics-color=always', '-I/usr/local/include'], CPPPATH='..', LINKFLAGS='-L/usr/local/lib') diff --git a/test/SConstruct b/test/SConstruct index a37669b5..b35f286c 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -2,10 +2,9 @@ import os env = Environment( ENV = os.environ, - CXX='c++', + CXX='c++' CXXFLAGS= ['-g', '-Wall', '-Wextra', '-pedantic', '-std=c++11', - '-fdiagnostics-color=always', '-I/usr/local/include', '-I.'], CPPPATH='..', LINKFLAGS='-L/usr/local/lib') @@ -54,6 +53,8 @@ conf = Configure(env) # if catch isn't available, exit if not conf.CheckCXXHeader('catch.hpp'): print("WARNING: catch.hpp not found, run ./download_catch.sh first") + print("note: you may receive this warning if the c++ compiler specified " + "by CXX at the top of the SConstruct file is invalid.") Exit(1) if conf.CheckCXXHeader('boost/optional.hpp'): From dcb4a7f264438b9a574ba2a2fbe7ffaa6aa06584 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 27 Aug 2015 22:27:17 -0700 Subject: [PATCH 1306/1866] adds back missing comma --- test/SConstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/SConstruct b/test/SConstruct index b35f286c..129c2dbf 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -2,7 +2,7 @@ import os env = Environment( ENV = os.environ, - CXX='c++' + CXX='c++', CXXFLAGS= ['-g', '-Wall', '-Wextra', '-pedantic', '-std=c++11', '-I/usr/local/include', '-I.'], From 93177acc9bd7b32b779601106eb394534d09b0c5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 27 Aug 2015 22:42:37 -0700 Subject: [PATCH 1307/1866] 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 1308/1866] 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 1309/1866] 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 1310/1866] 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 1311/1866] 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 1312/1866] 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 f175c2384e8df4c800ec6d3a0cf9e115bf055f1c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 11:11:07 -0700 Subject: [PATCH 1313/1866] download_catch switched to download from master instead of the devel branch which has a bunch of compiler errors. --- test/download_catch.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/download_catch.sh b/test/download_catch.sh index b373a2c4..f88f5643 100755 --- a/test/download_catch.sh +++ b/test/download_catch.sh @@ -1,2 +1,2 @@ #!/usr/bin/env sh -wget -c https://raw.githubusercontent.com/philsquared/Catch/develop/single_include/catch.hpp +wget -c https://raw.githubusercontent.com/philsquared/Catch/master/single_include/catch.hpp From e08a1b8d63b2bc19437e95b17320a2aa03ae9aa9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 20:59:14 -0700 Subject: [PATCH 1314/1866] adds a test that a class is move-constructible only not assignable at all, not copy constructible --- test/helpers.hpp | 313 ++++++++++++++++++++++++----------------------- 1 file changed, 158 insertions(+), 155 deletions(-) diff --git a/test/helpers.hpp b/test/helpers.hpp index 06d0e035..39864222 100644 --- a/test/helpers.hpp +++ b/test/helpers.hpp @@ -9,107 +9,101 @@ namespace itertest { -// non-copyable. non-movable. non-default-constructible -class SolidInt { - private: - const int i; - public: - constexpr SolidInt(int n) - : i{n} - { } - - constexpr int getint() const { - return this->i; - } - - SolidInt() = delete; - SolidInt(const SolidInt&) = delete; - SolidInt& operator=(const SolidInt&) = delete; - SolidInt& operator=(SolidInt&&) = delete; - SolidInt(SolidInt&&) = delete; -}; - -namespace { + // non-copyable. non-movable. non-default-constructible + class SolidInt { + private: + const int i; + + public: + constexpr SolidInt(int n) : i{n} {} + + constexpr int getint() const { + return this->i; + } + + SolidInt() = delete; + SolidInt(const SolidInt&) = delete; + SolidInt& operator=(const SolidInt&) = delete; + SolidInt& operator=(SolidInt&&) = delete; + SolidInt(SolidInt&&) = delete; + }; + + namespace { struct DoubleDereferenceError : std::exception { - const char *what() const noexcept override { - return "Iterator dereferenced twice without increment"; - } + const char* what() const noexcept override { + return "Iterator dereferenced twice without increment"; + } }; // this class's iterator will throw if it's dereference twice without // an increment in between class InputIterable { - public: - class Iterator { - private: - int i; - bool was_incremented = true; - - public: - Iterator(int n) - : i{n} - { } - - Iterator& operator++() { - ++this->i; - this->was_incremented = true; - return *this; - } - - int operator*() { - if (!this->was_incremented) { - throw DoubleDereferenceError{}; - } - this->was_incremented = false; - return this->i; - } - - bool operator!=(const Iterator& other) const { - return this->i != other.i; - } - }; - - Iterator begin() { - return {0}; - } - - Iterator end() { - return {5}; - } - }; -} - + public: + class Iterator { + private: + int i; + bool was_incremented = true; + + public: + Iterator(int n) : i{n} {} + + Iterator& operator++() { + ++this->i; + this->was_incremented = true; + return *this; + } + int operator*() { + if (!this->was_incremented) { + throw DoubleDereferenceError{}; + } + this->was_incremented = false; + return this->i; + } -// BasicIterable provides a minimal forward iterator -// operator++(), operator!=(const BasicIterable&), operator*() -// move constructible only -// not copy constructible, move assignable, or copy assignable -template -class BasicIterable { - private: - T *data; - std::size_t size; - bool was_moved_from_ = false; - bool was_copied_from_ = false; - public: - BasicIterable(std::initializer_list il) - : data{new T[il.size()]}, - size{il.size()} - { - // would like to use enumerate, can't because it's for unit - // testing enumerate - std::size_t i = 0; - for (auto&& e : il) { - data[i] = e; - ++i; - } + bool operator!=(const Iterator& other) const { + return this->i != other.i; } + }; - BasicIterable& operator=(BasicIterable&&) = delete; - BasicIterable& operator=(const BasicIterable&) = delete; + Iterator begin() { + return {0}; + } - BasicIterable(const BasicIterable&) = delete; + Iterator end() { + return {5}; + } + }; + } + + // BasicIterable provides a minimal forward iterator + // operator++(), operator!=(const BasicIterable&), operator*() + // move constructible only + // not copy constructible, move assignable, or copy assignable + template + class BasicIterable { + private: + T* data; + std::size_t size; + bool was_moved_from_ = false; + bool was_copied_from_ = false; + + public: + BasicIterable(std::initializer_list il) + : data{new T[il.size()]}, size{il.size()} { + // would like to use enumerate, can't because it's for unit + // testing enumerate + std::size_t i = 0; + for (auto&& e : il) { + data[i] = e; + ++i; + } + } + + BasicIterable& operator=(BasicIterable&&) = delete; + BasicIterable& operator=(const BasicIterable&) = delete; + + BasicIterable(const BasicIterable&) = delete; #if 0 BasicIterable(const BasicIterable& other) : data{new T[other.size()]}, @@ -123,79 +117,88 @@ class BasicIterable { } #endif + BasicIterable(BasicIterable&& other) : data{other.data}, size{other.size} { + other.data = nullptr; + other.was_moved_from_ = true; + } - BasicIterable(BasicIterable&& other) - : data{other.data}, - size{other.size} - { - other.data = nullptr; - other.was_moved_from_ = true; - } + bool was_moved_from() const { + return this->was_moved_from_; + } - bool was_moved_from() const { - return this->was_moved_from_; - } + bool was_copied_from() const { + return this->was_copied_from_; + } - bool was_copied_from() const { - return this->was_copied_from_; - } + ~BasicIterable() { + delete[] this->data; + } - ~BasicIterable() { - delete [] this->data; - } + class Iterator { + private: + T* p; - class Iterator { - private: - T *p; - public: + public: #ifdef DEFINE_DEFAULT_ITERATOR_CTOR - Iterator() = default; + Iterator() = default; #endif - Iterator(T *b) : p{b} { } - bool operator!=(const Iterator& other) const { - return this->p != other.p; - } - - Iterator& operator++() { - ++this->p; - return *this; - } - - T& operator*() { - return *this->p; - } - }; - - Iterator begin() { - return {this->data}; - } - - Iterator end() { - return {this->data + this->size}; - } -}; - -using iter::impl::void_t; - -template -struct IsIterator : std::false_type { }; - -template -struct IsIterator ())), // copyctor - decltype(std::declval() = std::declval()), // copy = - decltype(*std::declval()), // operator* - decltype(std::declval().operator->()), // operator-> - decltype(++std::declval()), // prefix ++ - decltype(std::declval()++), // postfix ++ - decltype(std::declval() != std::declval()), // != - decltype(std::declval() == std::declval()) // == - >> : std::true_type { }; - -template -struct IsForwardIterator : std::integral_constant::value && std::is_default_constructible::value> { }; + Iterator(T* b) : p{b} {} + bool operator!=(const Iterator& other) const { + return this->p != other.p; + } + + Iterator& operator++() { + ++this->p; + return *this; + } + + T& operator*() { + return *this->p; + } + }; + Iterator begin() { + return {this->data}; + } + + Iterator end() { + return {this->data + this->size}; + } + }; + + using iter::impl::void_t; + + template + struct IsIterator : std::false_type {}; + + template + struct IsIterator())), // copyctor + decltype(std::declval() = + std::declval()), // copy = + decltype(*std::declval()), // operator* + decltype( + std::declval().operator->()), // operator-> + decltype(++std::declval()), // prefix ++ + decltype(std::declval()++), // postfix ++ + decltype(std::declval() + != std::declval()), // != + decltype(std::declval() + == std::declval()) // == + >> : std::true_type {}; + + template + struct IsForwardIterator + : std::integral_constant::value && std::is_default_constructible::value> {}; + + template + struct IsMoveConstructibleOnly + : std::integral_constant::value + && !std::is_copy_assignable::value + && !std::is_move_assignable::value + && std::is_move_constructible::value> {}; } #endif From a1f9e1d537dc89fd083e21344dd7c13de6a5f02d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 21:01:44 -0700 Subject: [PATCH 1315/1866] tests IsMoveConstructibleOnly --- test/test_helpers.cpp | 44 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/test/test_helpers.cpp b/test/test_helpers.cpp index 129a17d2..ad456f6c 100644 --- a/test/test_helpers.cpp +++ b/test/test_helpers.cpp @@ -5,6 +5,7 @@ using itertest::SolidInt; using itertest::IsIterator; +using itertest::IsMoveConstructibleOnly; namespace { @@ -81,3 +82,46 @@ TEST_CASE("IsIterator fails when missing copy assignment", "[helpers]") { TEST_CASE("IsIterator passes a valid iterator", "[helpers]") { REQUIRE( IsIterator::value ); } + +struct HasNothing { + HasNothing(const HasNothing&) = delete; + HasNothing& operator=(const HasNothing&) = delete; +}; + +struct HasMoveAndCopyCtor { + HasMoveAndCopyCtor(const HasMoveAndCopyCtor&); + HasMoveAndCopyCtor(HasMoveAndCopyCtor&&); +}; + +struct HasMoveCtorAndAssign { + HasMoveCtorAndAssign(HasMoveCtorAndAssign&&); + HasMoveCtorAndAssign& operator=(HasMoveCtorAndAssign&&); +}; + +struct HasMoveCtorAndCopyAssign { + HasMoveCtorAndCopyAssign(HasMoveCtorAndCopyAssign&&); + HasMoveCtorAndCopyAssign& operator=(const HasMoveCtorAndCopyAssign&); +}; + +struct HasMoveCtorOnly { + HasMoveCtorOnly(HasMoveCtorOnly&&); +}; + +TEST_CASE("IsMoveConstructibleOnly false without move ctor", "[helpers]") { + REQUIRE_FALSE( IsMoveConstructibleOnly::value ); +} + +TEST_CASE("IsMoveConstructibleOnly false with copy ctor", "[helpers]") { + REQUIRE_FALSE( IsMoveConstructibleOnly::value ); +} + +TEST_CASE("IsMoveConstructibleOnly false with move assign", "[helpers]") { + REQUIRE_FALSE( IsMoveConstructibleOnly::value ); +} +TEST_CASE("IsMoveConstructibleOnly false with copy assign", "[helpers]") { + REQUIRE_FALSE( IsMoveConstructibleOnly::value ); +} + +TEST_CASE("IsMoveConstructibleOnly true when met", "[helpers]") { + REQUIRE( IsMoveConstructibleOnly::value ); +} From 0711b74d8df835ece4556b1d9bfe232255dabedc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:21:19 -0700 Subject: [PATCH 1316/1866] tests accum impl has move ctor only --- test/test_accumulate.cpp | 101 +++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 47 deletions(-) diff --git a/test/test_accumulate.cpp b/test/test_accumulate.cpp index 1a4e9413..0d60f927 100644 --- a/test/test_accumulate.cpp +++ b/test/test_accumulate.cpp @@ -12,84 +12,91 @@ using itertest::BasicIterable; using Vec = const std::vector; TEST_CASE("Simple sum", "[accumulate]") { - Vec ns{1,2,3,4,5}; - auto a = accumulate(ns); + Vec ns{1, 2, 3, 4, 5}; + auto a = accumulate(ns); - Vec v(std::begin(a), std::end(a)); - Vec vc{1,3,6,10,15}; - REQUIRE( v == vc ); + Vec v(std::begin(a), std::end(a)); + Vec vc{1, 3, 6, 10, 15}; + REQUIRE(v == vc); } TEST_CASE("accumulate: With subtraction lambda", "[accumulate]") { - Vec ns{5,4,3,2,1}; - auto a = accumulate(ns, [](int a, int b){return a - b; }); + Vec ns{5, 4, 3, 2, 1}; + auto a = accumulate(ns, [](int a, int b) { return a - b; }); - Vec v(std::begin(a), std::end(a)); - Vec vc{5, 1, -2, -4, -5}; - REQUIRE( v == vc ); + Vec v(std::begin(a), std::end(a)); + Vec vc{5, 1, -2, -4, -5}; + REQUIRE(v == vc); } TEST_CASE("accumulate: with initializer_list works", "[accumulate]") { - auto a = accumulate({1, 2, 3}); - Vec v(std::begin(a), std::end(a)); - Vec vc{1, 3, 6}; + auto a = accumulate({1, 2, 3}); + Vec v(std::begin(a), std::end(a)); + Vec vc{1, 3, 6}; - REQUIRE( v == vc ); + REQUIRE(v == vc); } struct Integer { - const int value; - constexpr Integer(int i) : value{i} { } - constexpr Integer operator+(Integer other) const noexcept { - return {this->value + other.value}; - } + const int value; + constexpr Integer(int i) : value{i} {} + constexpr Integer operator+(Integer other) const noexcept { + return {this->value + other.value}; + } }; TEST_CASE("accumulate: intermidate type need not be default constructible", - "[accumulate]") { - std::vector v = {{2}, {3}, {10}}; - auto a = accumulate(v, std::plus{}); - auto it = std::begin(a); + "[accumulate]") { + std::vector v = {{2}, {3}, {10}}; + auto a = accumulate(v, std::plus{}); + auto it = std::begin(a); } TEST_CASE("accumulate: binds reference when it should", "[accumulate]") { - BasicIterable bi{1, 2}; - accumulate(bi); - REQUIRE_FALSE( bi.was_moved_from() ); + BasicIterable bi{1, 2}; + accumulate(bi); + REQUIRE_FALSE(bi.was_moved_from()); } TEST_CASE("accumulate: moves rvalues when it should", "[accumulate]") { - BasicIterable bi{1, 2}; - accumulate(std::move(bi)); - REQUIRE( bi.was_moved_from() ); + BasicIterable bi{1, 2}; + accumulate(std::move(bi)); + REQUIRE(bi.was_moved_from()); } TEST_CASE("accumulate: operator==", "[accumulate]") { - Vec v; - auto a = accumulate(v); - REQUIRE( std::begin(a) == std::end(a) ); + Vec v; + auto a = accumulate(v); + REQUIRE(std::begin(a) == std::end(a)); } TEST_CASE("accumulate: postfix ++", "[accumulate]") { - Vec ns{2,3}; - auto a = accumulate(ns); - auto it = std::begin(a); - it++; - REQUIRE( *it == 5 ); + Vec ns{2, 3}; + auto a = accumulate(ns); + auto it = std::begin(a); + it++; + REQUIRE(*it == 5); } TEST_CASE("accumulate: operator->", "[accumulate]") { - Vec ns{7, 3}; - auto a = accumulate(ns); - auto it = std::begin(a); - const int *p = it.operator->(); - REQUIRE( *p == 7 ); + Vec ns{7, 3}; + auto a = accumulate(ns); + auto it = std::begin(a); + const int* p = it.operator->(); + REQUIRE(*p == 7); } TEST_CASE("accumulate: iterator meets requirements", "[accumulate]") { - Vec ns{}; - auto a = accumulate(ns, [](int a, int b) { return a + b; }); - auto it = std::begin(a); - it = std::begin(a); - REQUIRE( itertest::IsIterator::value ); + Vec ns{}; + auto a = accumulate(ns, [](int a, int b) { return a + b; }); + auto it = std::begin(a); + it = std::begin(a); + REQUIRE(itertest::IsIterator::value); +} + +template +using ImpT = decltype(accumulate(std::declval())); +TEST_CASE("accumulate: has correct ctor and assign ops", "[accumulate]") { + REQUIRE(itertest::IsMoveConstructibleOnly>::value); + REQUIRE(itertest::IsMoveConstructibleOnly>::value); } From b7695785b02d20d877dcffebbbae42276dceffb1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:21:36 -0700 Subject: [PATCH 1317/1866] tests chain impl has move ctor only --- test/test_chain.cpp | 292 +++++++++++++++++++++++--------------------- 1 file changed, 154 insertions(+), 138 deletions(-) diff --git a/test/test_chain.cpp b/test/test_chain.cpp index 46319d33..85844900 100644 --- a/test/test_chain.cpp +++ b/test/test_chain.cpp @@ -16,200 +16,216 @@ using itertest::BasicIterable; using Vec = const std::vector; TEST_CASE("chain: three strings", "[chain]") { - std::string s1{"abc"}; - std::string s2{"mno"}; - std::string s3{"xyz"}; - auto ch = chain(s1, s2, s3); + std::string s1{"abc"}; + std::string s2{"mno"}; + std::string s3{"xyz"}; + auto ch = chain(s1, s2, s3); - Vec v(std::begin(ch), std::end(ch)); - Vec vc{'a','b','c','m','n','o','x','y','z'}; + Vec v(std::begin(ch), std::end(ch)); + Vec vc{'a', 'b', 'c', 'm', 'n', 'o', 'x', 'y', 'z'}; - REQUIRE( v == vc ); + REQUIRE(v == vc); } TEST_CASE("chain: with different container types", "[chain]") { - std::string s1{"abc"}; - std::list li{'m', 'n', 'o'}; - std::vector vec{'x', 'y', 'z'}; - auto ch = chain(s1, li, vec); + std::string s1{"abc"}; + std::list li{'m', 'n', 'o'}; + std::vector vec{'x', 'y', 'z'}; + auto ch = chain(s1, li, vec); - Vec v(std::begin(ch), std::end(ch)); - Vec vc{'a','b','c','m','n','o','x','y','z'}; + Vec v(std::begin(ch), std::end(ch)); + Vec vc{'a', 'b', 'c', 'm', 'n', 'o', 'x', 'y', 'z'}; - REQUIRE( v == vc ); + REQUIRE(v == vc); } TEST_CASE("chain: handles empty containers", "[chain]") { - std::string emp; - std::string a{"a"}; - std::string b{"b"}; - std::string c{"c"}; - Vec vc{'a', 'b', 'c'}; - - SECTION("Empty container at front") { - auto ch = chain(emp, a, b, c); - Vec v(std::begin(ch), std::end(ch)); + std::string emp; + std::string a{"a"}; + std::string b{"b"}; + std::string c{"c"}; + Vec vc{'a', 'b', 'c'}; + + SECTION("Empty container at front") { + auto ch = chain(emp, a, b, c); + Vec v(std::begin(ch), std::end(ch)); - REQUIRE( v == vc ); - } + REQUIRE(v == vc); + } - SECTION("Empty container at back") { - auto ch = chain(a, b, c, emp); - Vec v(std::begin(ch), std::end(ch)); + SECTION("Empty container at back") { + auto ch = chain(a, b, c, emp); + Vec v(std::begin(ch), std::end(ch)); - REQUIRE( v == vc ); - } + REQUIRE(v == vc); + } - SECTION("Empty container in middle") { - auto ch = chain(a, emp, b, emp, c); - Vec v(std::begin(ch), std::end(ch)); + SECTION("Empty container in middle") { + auto ch = chain(a, emp, b, emp, c); + Vec v(std::begin(ch), std::end(ch)); - REQUIRE( v == vc ); - } + REQUIRE(v == vc); + } - SECTION("Consecutive empty containers at front") { - auto ch = chain(emp, emp, a, b, c); - Vec v(std::begin(ch), std::end(ch)); + SECTION("Consecutive empty containers at front") { + auto ch = chain(emp, emp, a, b, c); + Vec v(std::begin(ch), std::end(ch)); - REQUIRE( v == vc ); - } + REQUIRE(v == vc); + } - SECTION("Consecutive empty containers at back") { - auto ch = chain(a, b, c, emp, emp); - Vec v(std::begin(ch), std::end(ch)); + SECTION("Consecutive empty containers at back") { + auto ch = chain(a, b, c, emp, emp); + Vec v(std::begin(ch), std::end(ch)); - REQUIRE( v == vc ); - } + REQUIRE(v == vc); + } - SECTION("Consecutive empty containers in middle") { - auto ch = chain(a, emp, emp, b, emp, emp, c); - Vec v(std::begin(ch), std::end(ch)); + SECTION("Consecutive empty containers in middle") { + auto ch = chain(a, emp, emp, b, emp, emp, c); + Vec v(std::begin(ch), std::end(ch)); - REQUIRE( v == vc ); - } + REQUIRE(v == vc); + } } TEST_CASE("chain: with only empty containers", "[chain]") { - std::string emp{}; - SECTION("one empty container") { - auto ch = chain(emp); - REQUIRE_FALSE( std::begin(ch) != std::end(ch) ); - } - - SECTION("two empty containers") { - auto ch = chain(emp, emp); - REQUIRE_FALSE( std::begin(ch) != std::end(ch) ); - } - - SECTION("three empty containers") { - auto ch = chain(emp, emp, emp); - REQUIRE_FALSE( std::begin(ch) != std::end(ch) ); - } + std::string emp{}; + SECTION("one empty container") { + auto ch = chain(emp); + REQUIRE_FALSE(std::begin(ch) != std::end(ch)); + } + + SECTION("two empty containers") { + auto ch = chain(emp, emp); + REQUIRE_FALSE(std::begin(ch) != std::end(ch)); + } + + SECTION("three empty containers") { + auto ch = chain(emp, emp, emp); + REQUIRE_FALSE(std::begin(ch) != std::end(ch)); + } } TEST_CASE("chain: doesn't move or copy elements of iterable", "[chain]") { - constexpr SolidInt arr[] = {{6}, {7}, {8}}; - for (auto&& i : chain(arr, arr)) { - (void)i; - } + constexpr SolidInt arr[] = {{6}, {7}, {8}}; + for (auto&& i : chain(arr, arr)) { + (void)i; + } } TEST_CASE("chain: binds reference to lvalue and moves rvalue", "[chain]") { - BasicIterable bi{'x', 'y', 'z'}; - BasicIterable bi2{'a', 'j', 'm'}; - SECTION("First moved, second ref'd") { - chain(std::move(bi), bi2); - REQUIRE( bi.was_moved_from() ); - REQUIRE_FALSE( bi2.was_moved_from() ); - } - SECTION("First ref'd, second moved") { - chain(bi, std::move(bi2)); - REQUIRE_FALSE( bi.was_moved_from() ); - REQUIRE( bi2.was_moved_from() ); - } + BasicIterable bi{'x', 'y', 'z'}; + BasicIterable bi2{'a', 'j', 'm'}; + SECTION("First moved, second ref'd") { + chain(std::move(bi), bi2); + REQUIRE(bi.was_moved_from()); + REQUIRE_FALSE(bi2.was_moved_from()); + } + SECTION("First ref'd, second moved") { + chain(bi, std::move(bi2)); + REQUIRE_FALSE(bi.was_moved_from()); + REQUIRE(bi2.was_moved_from()); + } } TEST_CASE("chain: operator==", "[chain]") { - std::string emp{}; - auto ch = chain(emp); - REQUIRE( std::begin(ch) == std::end(ch) ); + std::string emp{}; + auto ch = chain(emp); + REQUIRE(std::begin(ch) == std::end(ch)); } TEST_CASE("chain: postfix ++", "[chain]") { - std::string s1{"a"}, s2{"b"}; - auto ch = chain(s1, s2); - auto it = std::begin(ch); - it++; - REQUIRE( *it == 'b'); + std::string s1{"a"}, s2{"b"}; + auto ch = chain(s1, s2); + auto it = std::begin(ch); + it++; + REQUIRE(*it == 'b'); } TEST_CASE("chain: iterator meets requirements", "[chain]") { - Vec ns{}; - auto c = chain(ns, ns); - REQUIRE( itertest::IsIterator::value ); + Vec ns{}; + auto c = chain(ns, ns); + REQUIRE(itertest::IsIterator::value); } +template +using ImpT = decltype(chain(std::declval()...)); +TEST_CASE("chain: has correct ctor and assign ops", "[chain]") { + using T = ImpT, char[10]>; + REQUIRE(itertest::IsMoveConstructibleOnly::value); +} TEST_CASE("chain.from_iterable: basic test", "[chain.from_iterable]") { - std::vector sv{"abc", "xyz"}; - auto ch = chain.from_iterable(sv); - std::vector v(std::begin(ch), std::end(ch)); + std::vector sv{"abc", "xyz"}; + auto ch = chain.from_iterable(sv); + std::vector v(std::begin(ch), std::end(ch)); - std::vector vc{'a', 'b', 'c', 'x', 'y', 'z'}; - REQUIRE( v == vc ); + std::vector vc{'a', 'b', 'c', 'x', 'y', 'z'}; + REQUIRE(v == vc); } -TEST_CASE("chain.from_iterable: iterators cant be copy constructed " - "and assigned", "[chain.from_iterable]") { - std::vector sv{"abc", "xyz"}; - auto ch = chain.from_iterable(sv); - auto it = std::begin(ch); - - SECTION("Copy constructed") { - auto it2 = it; - ++it; - REQUIRE( it != it2 ); - } - - SECTION("Copy assigned") { - auto it2 = std::end(ch); - it2 = it; - REQUIRE( it == it2 ); - } +TEST_CASE( + "chain.from_iterable: iterators cant be copy constructed " + "and assigned", + "[chain.from_iterable]") { + std::vector sv{"abc", "xyz"}; + auto ch = chain.from_iterable(sv); + auto it = std::begin(ch); + + SECTION("Copy constructed") { + auto it2 = it; + ++it; + REQUIRE(it != it2); + } + + SECTION("Copy assigned") { + auto it2 = std::end(ch); + it2 = it; + REQUIRE(it == it2); + } } TEST_CASE("chain.from_iterable: postfix ++", "[chain.from_iterable]") { - std::vector sv{"a", "n"}; - auto ch = chain.from_iterable(sv); - auto it = std::begin(ch); - it++; - REQUIRE( *it == 'n' ); + std::vector sv{"a", "n"}; + auto ch = chain.from_iterable(sv); + auto it = std::begin(ch); + it++; + REQUIRE(*it == 'n'); } - TEST_CASE("chain.from_iterable: moves rvalues and binds ref to lvalues", - "[chain.from_iterable]") { - BasicIterable bi{"abc", "xyz"}; - SECTION("Moves rvalue") { - chain.from_iterable(std::move(bi)); - REQUIRE( bi.was_moved_from() ); - } - SECTION("Binds ref to lvalue") { - chain.from_iterable(bi); - REQUIRE_FALSE( bi.was_moved_from() ); - } + "[chain.from_iterable]") { + BasicIterable bi{"abc", "xyz"}; + SECTION("Moves rvalue") { + chain.from_iterable(std::move(bi)); + REQUIRE(bi.was_moved_from()); + } + SECTION("Binds ref to lvalue") { + chain.from_iterable(bi); + REQUIRE_FALSE(bi.was_moved_from()); + } } TEST_CASE("chain.from_iterable: empty", "[chain.from_iterable]") { - const std::vector v{}; - auto ch = chain.from_iterable(v); - REQUIRE( std::begin(ch) == std::end(ch) ); + const std::vector v{}; + auto ch = chain.from_iterable(v); + REQUIRE(std::begin(ch) == std::end(ch)); } - TEST_CASE("chain.from_iterable: iterator meets requirements", - "[chain.from_iterable]") { - const std::vector v{}; - auto c = chain.from_iterable(v); - REQUIRE( itertest::IsIterator::value ); + "[chain.from_iterable]") { + const std::vector v{}; + auto c = chain.from_iterable(v); + REQUIRE(itertest::IsIterator::value); +} + +template +using ImpT2 = decltype(chain.from_iterable(std::declval())); +TEST_CASE("chain.from_iterable: has correct ctor and assign ops", + "[chain.from_iterable]") { + REQUIRE(itertest::IsMoveConstructibleOnly>>:: + value); + REQUIRE(itertest::IsMoveConstructibleOnly&>>:: + value); } From 030ad33b2d85d86150a221327103f675d63fdb3d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:21:45 -0700 Subject: [PATCH 1318/1866] tests chunked impl has move ctor only --- test/test_chunked.cpp | 69 ++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/test/test_chunked.cpp b/test/test_chunked.cpp index e77429b0..16c948ed 100644 --- a/test/test_chunked.cpp +++ b/test/test_chunked.cpp @@ -13,54 +13,61 @@ using Vec = std::vector; using ResVec = std::vector; TEST_CASE("chunked: basic test", "[chunked]") { - Vec ns = {1,2,3,4,5,6}; - ResVec results; - for (auto&& g : chunked(ns, 2)) { - results.emplace_back(std::begin(g), std::end(g)); - } + Vec ns = {1, 2, 3, 4, 5, 6}; + ResVec results; + for (auto&& g : chunked(ns, 2)) { + results.emplace_back(std::begin(g), std::end(g)); + } - ResVec rc = { {1, 2}, {3, 4}, {5, 6} }; + ResVec rc = {{1, 2}, {3, 4}, {5, 6}}; - REQUIRE( results == rc ); + REQUIRE(results == rc); } TEST_CASE("chunked: len(iterable) % groupsize != 0", "[chunked]") { - Vec ns = {1,2,3,4,5,6,7}; - ResVec results; - for (auto&& g : chunked(ns, 3)) { - results.emplace_back(std::begin(g), std::end(g)); - } + Vec ns = {1, 2, 3, 4, 5, 6, 7}; + ResVec results; + for (auto&& g : chunked(ns, 3)) { + results.emplace_back(std::begin(g), std::end(g)); + } - ResVec rc = { {1, 2, 3}, {4, 5, 6}, {7} }; + ResVec rc = {{1, 2, 3}, {4, 5, 6}, {7}}; - REQUIRE( results == rc ); + REQUIRE(results == rc); } TEST_CASE("chunked: iterators can be compared", "[chunked]") { - Vec ns = {1,2,3,4,5,6,7}; - auto g = chunked(ns, 3); - auto it = std::begin(g); - REQUIRE( it == std::begin(g) ); - REQUIRE_FALSE( it != std::begin(g) ); - ++it; - REQUIRE( it != std::begin(g) ); - REQUIRE_FALSE( it == std::begin(g) ); + Vec ns = {1, 2, 3, 4, 5, 6, 7}; + auto g = chunked(ns, 3); + auto it = std::begin(g); + REQUIRE(it == std::begin(g)); + REQUIRE_FALSE(it != std::begin(g)); + ++it; + REQUIRE(it != std::begin(g)); + REQUIRE_FALSE(it == std::begin(g)); } TEST_CASE("chunked: size 0 is empty", "[chunked]") { - Vec ns{1, 2, 3}; - auto g = chunked(ns, 0); - REQUIRE( std::begin(g) == std::end(g) ); + Vec ns{1, 2, 3}; + auto g = chunked(ns, 0); + REQUIRE(std::begin(g) == std::end(g)); } TEST_CASE("chunked: empty iterable gives empty chunked", "[chunked]") { - Vec ns{}; - auto g = chunked(ns, 1); - REQUIRE( std::begin(g) == std::end(g) ); + Vec ns{}; + auto g = chunked(ns, 1); + REQUIRE(std::begin(g) == std::end(g)); } TEST_CASE("chunked: iterator meets requirements", "[chunked]") { - std::string s{}; - auto c = chunked(s, 1); - REQUIRE( itertest::IsIterator::value ); + std::string s{}; + auto c = chunked(s, 1); + REQUIRE(itertest::IsIterator::value); +} + +template +using ImpT = decltype(chunked(std::declval(), 1)); +TEST_CASE("chunked: has correct ctor and assign ops", "[chunked]") { + REQUIRE(itertest::IsMoveConstructibleOnly>::value); + REQUIRE(itertest::IsMoveConstructibleOnly>::value); } From 5de4b7d0ac50e6b62b23d1f881b911f7c622f861 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:21:58 -0700 Subject: [PATCH 1319/1866] tests comb impl has move ctor only --- test/test_combinations.cpp | 115 +++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 55 deletions(-) diff --git a/test/test_combinations.cpp b/test/test_combinations.cpp index 278c6225..5ce91e6e 100644 --- a/test/test_combinations.cpp +++ b/test/test_combinations.cpp @@ -11,88 +11,93 @@ #include "catch.hpp" - using iter::combinations; using itertest::BasicIterable; using itertest::SolidInt; using CharCombSet = std::vector>; TEST_CASE("combinations: Simple combination of 4", "[combinations]") { - std::string s{"ABCD"}; - CharCombSet sc; - for (auto v : combinations(s, 2)) { - sc.emplace_back(std::begin(v), std::end(v)); - } - - CharCombSet ans = - {{'A','B'}, {'A','C'}, {'A','D'}, {'B','C'}, {'B','D'}, {'C','D'}}; - REQUIRE( ans == sc ); + std::string s{"ABCD"}; + CharCombSet sc; + for (auto v : combinations(s, 2)) { + sc.emplace_back(std::begin(v), std::end(v)); + } + + CharCombSet ans = { + {'A', 'B'}, {'A', 'C'}, {'A', 'D'}, {'B', 'C'}, {'B', 'D'}, {'C', 'D'}}; + REQUIRE(ans == sc); } TEST_CASE("combinations: iterators can be compared", "[combinations]") { - std::string s{"ABCD"}; - auto c = combinations(s, 2); - auto it = std::begin(c); - REQUIRE( it == std::begin(c) ); - REQUIRE_FALSE( it != std::begin(c) ); - ++it; - REQUIRE( it != std::begin(c) ); - REQUIRE_FALSE( it == std::begin(c) ); + std::string s{"ABCD"}; + auto c = combinations(s, 2); + auto it = std::begin(c); + REQUIRE(it == std::begin(c)); + REQUIRE_FALSE(it != std::begin(c)); + ++it; + REQUIRE(it != std::begin(c)); + REQUIRE_FALSE(it == std::begin(c)); } TEST_CASE("combinations: operator->", "[combinations]") { - std::string s{"ABCD"}; - auto c = combinations(s, 2); - auto it = std::begin(c); - REQUIRE( it->size() == 2 ); + std::string s{"ABCD"}; + auto c = combinations(s, 2); + auto it = std::begin(c); + REQUIRE(it->size() == 2); } - TEST_CASE("combinations: size too large gives no results", "[combinations]") { - std::string s{"ABCD"}; - auto c = combinations(s, 5); - REQUIRE( std::begin(c) == std::end(c) ); + std::string s{"ABCD"}; + auto c = combinations(s, 5); + REQUIRE(std::begin(c) == std::end(c)); } TEST_CASE("combinations: size 0 gives nothing", "[combinations]") { - std::string s{"ABCD"}; - auto c = combinations(s, 0); - REQUIRE( std::begin(c) == std::end(c) ); + std::string s{"ABCD"}; + auto c = combinations(s, 0); + REQUIRE(std::begin(c) == std::end(c)); } -TEST_CASE("combinations: iterable without operator*() const", "[combinations]") -{ - BasicIterable bi{'x', 'y', 'z'}; - auto c = combinations(bi, 1); - auto it = std::begin(c); - ++it; - (*it)[0]; +TEST_CASE( + "combinations: iterable without operator*() const", "[combinations]") { + BasicIterable bi{'x', 'y', 'z'}; + auto c = combinations(bi, 1); + auto it = std::begin(c); + ++it; + (*it)[0]; } TEST_CASE("combinations: binds to lvalues, moves rvalues", "[combinations]") { - BasicIterable bi{'x', 'y', 'z'}; - SECTION("binds to lvalues") { - combinations(bi, 1); - REQUIRE_FALSE( bi.was_moved_from() ); - } - SECTION("moves rvalues") { - combinations(std::move(bi), 1); - REQUIRE( bi.was_moved_from() ); - } + BasicIterable bi{'x', 'y', 'z'}; + SECTION("binds to lvalues") { + combinations(bi, 1); + REQUIRE_FALSE(bi.was_moved_from()); + } + SECTION("moves rvalues") { + combinations(std::move(bi), 1); + REQUIRE(bi.was_moved_from()); + } } TEST_CASE("combinations: doesn't move or copy elements of iterable", - "[combinations]") { - constexpr SolidInt arr[] = {{6}, {7}, {8}}; - for (auto&& i : combinations(arr, 1)) { - (void)i; - } + "[combinations]") { + constexpr SolidInt arr[] = {{6}, {7}, {8}}; + for (auto&& i : combinations(arr, 1)) { + (void)i; + } } TEST_CASE("combinations: iterator meets requirements", "[combinations]") { - std::string s{"abc"}; - auto c = combinations(s, 1); - REQUIRE( itertest::IsIterator::value ); - auto&& row = *std::begin(c); - REQUIRE( itertest::IsIterator::value ); + std::string s{"abc"}; + auto c = combinations(s, 1); + REQUIRE(itertest::IsIterator::value); + auto&& row = *std::begin(c); + REQUIRE(itertest::IsIterator::value); +} + +template +using ImpT = decltype(combinations(std::declval(), 1)); +TEST_CASE("combinations: has correct ctor and assign ops", "[combinations]") { + REQUIRE(itertest::IsMoveConstructibleOnly>::value); + REQUIRE(itertest::IsMoveConstructibleOnly>::value); } From cc038b59b8f4766b77f3804ec08f39451b13f56e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:22:15 -0700 Subject: [PATCH 1320/1866] tests comb_w_repl impl has move ctor only --- test/test_combinations_with_replacement.cpp | 129 +++++++++++--------- 1 file changed, 69 insertions(+), 60 deletions(-) diff --git a/test/test_combinations_with_replacement.cpp b/test/test_combinations_with_replacement.cpp index e5e91f25..5f0fc4ef 100644 --- a/test/test_combinations_with_replacement.cpp +++ b/test/test_combinations_with_replacement.cpp @@ -13,83 +13,92 @@ using itertest::BasicIterable; using CharCombSet = std::vector>; TEST_CASE("combinations_with_replacement: Simple combination", - "[combinations_with_replacement]") { - std::string s{"ABC"}; - CharCombSet sc; - for (auto v : combinations_with_replacement(s, 2)) { - sc.emplace_back(std::begin(v), std::end(v)); - } - CharCombSet ans = - {{'A','A'}, {'A','B'}, {'A','C'}, {'B','B'}, {'B','C'}, {'C','C'}}; - REQUIRE( ans == sc ); + "[combinations_with_replacement]") { + std::string s{"ABC"}; + CharCombSet sc; + for (auto v : combinations_with_replacement(s, 2)) { + sc.emplace_back(std::begin(v), std::end(v)); + } + CharCombSet ans = { + {'A', 'A'}, {'A', 'B'}, {'A', 'C'}, {'B', 'B'}, {'B', 'C'}, {'C', 'C'}}; + REQUIRE(ans == sc); } TEST_CASE("combinations_with_replacement: iterators can be compared", - "[combinations_with_replacement]") { - std::string s{"ABCD"}; - auto c = combinations_with_replacement(s, 2); - auto it = std::begin(c); - REQUIRE( it == std::begin(c) ); - REQUIRE_FALSE( it != std::begin(c) ); - ++it; - REQUIRE( it != std::begin(c) ); - REQUIRE_FALSE( it == std::begin(c) ); + "[combinations_with_replacement]") { + std::string s{"ABCD"}; + auto c = combinations_with_replacement(s, 2); + auto it = std::begin(c); + REQUIRE(it == std::begin(c)); + REQUIRE_FALSE(it != std::begin(c)); + ++it; + REQUIRE(it != std::begin(c)); + REQUIRE_FALSE(it == std::begin(c)); } TEST_CASE("combinations_with_replacement: big size is no problem", - "[combinations_with_replacement]") { - std::string s{"AB"}; - CharCombSet sc; - for (auto v : combinations_with_replacement(s, 3)) { - sc.emplace_back(std::begin(v), std::end(v)); - } - CharCombSet ans = - {{'A', 'A', 'A'}, {'A', 'A', 'B'}, {'A', 'B', 'B'}, {'B', 'B', 'B'}}; - REQUIRE( ans == sc ); + "[combinations_with_replacement]") { + std::string s{"AB"}; + CharCombSet sc; + for (auto v : combinations_with_replacement(s, 3)) { + sc.emplace_back(std::begin(v), std::end(v)); + } + CharCombSet ans = { + {'A', 'A', 'A'}, {'A', 'A', 'B'}, {'A', 'B', 'B'}, {'B', 'B', 'B'}}; + REQUIRE(ans == sc); } - + TEST_CASE("combinations_with_replacement: 0 size is empty", - "[combinations_with_replacement]") { - std::string s{"A"}; - auto cwr = combinations_with_replacement(s, 0); - REQUIRE( std::begin(cwr) == std::end(cwr) ); + "[combinations_with_replacement]") { + std::string s{"A"}; + auto cwr = combinations_with_replacement(s, 0); + REQUIRE(std::begin(cwr) == std::end(cwr)); } TEST_CASE("combinations_with_replacement: operator->", - "[combinations_with_replacement]") { - std::string s{"ABCD"}; - auto c = combinations_with_replacement(s, 2); - auto it = std::begin(c); - REQUIRE( it->size() == 2 ); + "[combinations_with_replacement]") { + std::string s{"ABCD"}; + auto c = combinations_with_replacement(s, 2); + auto it = std::begin(c); + REQUIRE(it->size() == 2); } TEST_CASE("combinations_with_replacement: binds to lvalues, moves rvalues", - "[combinations_with_replacement]") { - BasicIterable bi{'x', 'y', 'z'}; - SECTION("binds to lvalues") { - combinations_with_replacement(bi, 1); - REQUIRE_FALSE( bi.was_moved_from() ); - } - SECTION("moves rvalues") { - combinations_with_replacement(std::move(bi), 1); - REQUIRE( bi.was_moved_from() ); - } + "[combinations_with_replacement]") { + BasicIterable bi{'x', 'y', 'z'}; + SECTION("binds to lvalues") { + combinations_with_replacement(bi, 1); + REQUIRE_FALSE(bi.was_moved_from()); + } + SECTION("moves rvalues") { + combinations_with_replacement(std::move(bi), 1); + REQUIRE(bi.was_moved_from()); + } } -TEST_CASE("combinations_with_replacement: " - "doesn't move or copy elements of iterable", - "[combinations_with_replacement]") { - constexpr itertest::SolidInt arr[] = {{6}, {7}, {8}}; - for (auto&& i : combinations_with_replacement(arr, 1)) { - (void)i; - } +TEST_CASE( + "combinations_with_replacement: " + "doesn't move or copy elements of iterable", + "[combinations_with_replacement]") { + constexpr itertest::SolidInt arr[] = {{6}, {7}, {8}}; + for (auto&& i : combinations_with_replacement(arr, 1)) { + (void)i; + } } TEST_CASE("combinations_with_replacement: iterator meets requirements", - "[combinations_with_replacement]") { - std::string s{"abc"}; - auto c = combinations_with_replacement(s, 1); - REQUIRE( itertest::IsIterator::value ); - auto&& row = *std::begin(c); - REQUIRE( itertest::IsIterator::value ); + "[combinations_with_replacement]") { + std::string s{"abc"}; + auto c = combinations_with_replacement(s, 1); + REQUIRE(itertest::IsIterator::value); + auto&& row = *std::begin(c); + REQUIRE(itertest::IsIterator::value); +} + +template +using ImpT = decltype(combinations_with_replacement(std::declval(), 1)); +TEST_CASE("combinations_with_replacement: has correct ctor and assign ops", + "[combinations_with_replacement]") { + REQUIRE(itertest::IsMoveConstructibleOnly>::value); + REQUIRE(itertest::IsMoveConstructibleOnly>::value); } From bc0efea91bcf1828c624b3e081e15f81db47b0e7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:22:27 -0700 Subject: [PATCH 1321/1866] tests compress impl has move ctor only --- test/test_compress.cpp | 156 ++++++++++++++++++++++------------------- 1 file changed, 82 insertions(+), 74 deletions(-) diff --git a/test/test_compress.cpp b/test/test_compress.cpp index 1152b60a..9a0c30b2 100644 --- a/test/test_compress.cpp +++ b/test/test_compress.cpp @@ -15,124 +15,132 @@ using itertest::BasicIterable; using Vec = const std::vector; TEST_CASE("compress: alternating", "[compress]") { - std::vector ivec{1, 2, 3, 4, 5, 6}; - std::vector bvec{true, false, true, false, true, false}; - auto c = compress(ivec, bvec); - Vec v(std::begin(c), std::end(c)); - Vec vc = {1,3,5}; + std::vector ivec{1, 2, 3, 4, 5, 6}; + std::vector bvec{true, false, true, false, true, false}; + auto c = compress(ivec, bvec); + Vec v(std::begin(c), std::end(c)); + Vec vc = {1, 3, 5}; - REQUIRE( v == vc ); + REQUIRE(v == vc); } TEST_CASE("compress: consecutive falses", "[compress]") { - std::vector ivec{1, 2, 3, 4, 5}; - std::vector bvec{true, false, false, false, true}; - auto c = compress(ivec, bvec); - Vec v(std::begin(c), std::end(c)); - Vec vc = {1,5}; + std::vector ivec{1, 2, 3, 4, 5}; + std::vector bvec{true, false, false, false, true}; + auto c = compress(ivec, bvec); + Vec v(std::begin(c), std::end(c)); + Vec vc = {1, 5}; - REQUIRE( v == vc ); + REQUIRE(v == vc); } TEST_CASE("compress: consecutive trues", "[compress]") { - std::vector ivec{1, 2, 3, 4, 5}; - std::vector bvec{false, true, true, true, false}; - auto c = compress(ivec, bvec); - Vec v(std::begin(c), std::end(c)); - Vec vc = {2,3,4}; + std::vector ivec{1, 2, 3, 4, 5}; + std::vector bvec{false, true, true, true, false}; + auto c = compress(ivec, bvec); + Vec v(std::begin(c), std::end(c)); + Vec vc = {2, 3, 4}; - REQUIRE( v == vc ); + REQUIRE(v == vc); } TEST_CASE("compress: all true", "[compress]") { - std::vector ivec{1, 2, 3, 4, 5}; - std::vector bvec(ivec.size(), true); - auto c = compress(ivec, bvec); - Vec v(std::begin(c), std::end(c)); + std::vector ivec{1, 2, 3, 4, 5}; + std::vector bvec(ivec.size(), true); + auto c = compress(ivec, bvec); + Vec v(std::begin(c), std::end(c)); - REQUIRE( v == ivec ); + REQUIRE(v == ivec); } TEST_CASE("compress: all false", "[compress]") { - std::vector ivec{1, 2, 3, 4, 5}; - std::vector bvec(ivec.size(), false); - auto c = compress(ivec, bvec); - REQUIRE( std::begin(c) == std::end(c) ); + std::vector ivec{1, 2, 3, 4, 5}; + std::vector bvec(ivec.size(), false); + auto c = compress(ivec, bvec); + REQUIRE(std::begin(c) == std::end(c)); } TEST_CASE("compress: operator->", "[compress") { - std::vector svec = {"a", "abc", "abcde"}; - std::vector bvec = {false, false, true}; - auto c = compress(svec, bvec); - auto it = std::begin(c); - REQUIRE( it->size() == 5 ); + std::vector svec = {"a", "abc", "abcde"}; + std::vector bvec = {false, false, true}; + auto c = compress(svec, bvec); + auto it = std::begin(c); + REQUIRE(it->size() == 5); } - TEST_CASE("compress: binds to lvalues, moves rvalues", "[compress]") { - BasicIterable bi{'x', 'y', 'z'}; - std::vector bl{true, true, true}; - SECTION("binds to lvalues") { - compress(bi, bl); - REQUIRE_FALSE( bi.was_moved_from() ); - } - SECTION("moves rvalues") { - compress(std::move(bi), bl); - REQUIRE( bi.was_moved_from() ); - } + BasicIterable bi{'x', 'y', 'z'}; + std::vector bl{true, true, true}; + SECTION("binds to lvalues") { + compress(bi, bl); + REQUIRE_FALSE(bi.was_moved_from()); + } + SECTION("moves rvalues") { + compress(std::move(bi), bl); + REQUIRE(bi.was_moved_from()); + } } struct BoolLike { - public: - bool state; - explicit operator bool() const { - return this->state; - } + public: + bool state; + explicit operator bool() const { + return this->state; + } }; TEST_CASE("compress: workds with truthy and falsey values", "[compress]") { - std::vector bvec{{true}, {false}, {true}, {false}}; + std::vector bvec{{true}, {false}, {true}, {false}}; - Vec ivec{1,2,3,4}; + Vec ivec{1, 2, 3, 4}; - auto c = compress(ivec, bvec); - Vec v(std::begin(c), std::end(c)); + auto c = compress(ivec, bvec); + Vec v(std::begin(c), std::end(c)); - Vec vc = {1,3}; - REQUIRE( v == vc ); + Vec vc = {1, 3}; + REQUIRE(v == vc); } TEST_CASE("compress: terminates on shorter selectors", "[compress]") { - std::vector ivec{1, 2, 3, 4, 5}; - std::vector bvec{true}; - auto c = compress(ivec, bvec); - REQUIRE( std::distance(std::begin(c), std::end(c)) == 1 ); + std::vector ivec{1, 2, 3, 4, 5}; + std::vector bvec{true}; + auto c = compress(ivec, bvec); + REQUIRE(std::distance(std::begin(c), std::end(c)) == 1); } TEST_CASE("compress: terminates on shorter data", "[compress]") { - std::vector ivec{1}; - std::vector bvec{true, true, true, true, true}; - auto c = compress(ivec, bvec); - REQUIRE( std::distance(std::begin(c), std::end(c)) == 1 ); + std::vector ivec{1}; + std::vector bvec{true, true, true, true, true}; + auto c = compress(ivec, bvec); + REQUIRE(std::distance(std::begin(c), std::end(c)) == 1); } TEST_CASE("compress: nothing on empty selectors", "[compress]") { - std::vector ivec{1,2,3}; - std::vector bvec{}; - auto c = compress(ivec, bvec); - REQUIRE( std::begin(c) == std::end(c) ); + std::vector ivec{1, 2, 3}; + std::vector bvec{}; + auto c = compress(ivec, bvec); + REQUIRE(std::begin(c) == std::end(c)); } TEST_CASE("compress: nothing on empty data", "[compress]") { - std::vector ivec{}; - std::vector bvec{true, true, true}; - auto c = compress(ivec, bvec); - REQUIRE( std::begin(c) == std::end(c) ); + std::vector ivec{}; + std::vector bvec{true, true, true}; + auto c = compress(ivec, bvec); + REQUIRE(std::begin(c) == std::end(c)); } TEST_CASE("compress: iterator meets requirements", "[compress]") { - std::string s{}; - std::vector bv; - auto c = compress(s, bv); - REQUIRE( itertest::IsIterator::value ); + std::string s{}; + std::vector bv; + auto c = compress(s, bv); + REQUIRE(itertest::IsIterator::value); +} + +template +using ImpT = decltype(compress(std::declval(), std::declval())); +TEST_CASE("compress: has correct ctor and assign ops", "[compress]") { + using T1 = ImpT&>; + using T2 = ImpT>; + REQUIRE(itertest::IsMoveConstructibleOnly::value); + REQUIRE(itertest::IsMoveConstructibleOnly::value); } From 8ac15c27cad164f8958442ea04d658d17b0e6098 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:22:48 -0700 Subject: [PATCH 1322/1866] tests cycle impl has move ctor only --- test/test_cycle.cpp | 78 ++++++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/test/test_cycle.cpp b/test/test_cycle.cpp index 5b09ab25..ea5bf3e7 100644 --- a/test/test_cycle.cpp +++ b/test/test_cycle.cpp @@ -11,55 +11,61 @@ using iter::cycle; TEST_CASE("cycle: iterate twice", "[cycle]") { - std::vector ns {2,4,6}; - std::vector v{}; - std::size_t count = 0; - for (auto i : cycle(ns)) { - v.push_back(i); - ++count; - if (count == ns.size() * 2) break; - } + std::vector ns{2, 4, 6}; + std::vector v{}; + std::size_t count = 0; + for (auto i : cycle(ns)) { + v.push_back(i); + ++count; + if (count == ns.size() * 2) break; + } - auto vc = ns; - vc.insert(std::end(vc), std::begin(ns), std::end(ns)); - REQUIRE( v == vc ); + auto vc = ns; + vc.insert(std::end(vc), std::begin(ns), std::end(ns)); + REQUIRE(v == vc); } TEST_CASE("cycle: empty cycle terminates", "[cycle]") { - std::vector ns; - auto c = cycle(ns); - std::vector v(std::begin(c), std::end(c)); - REQUIRE( v.empty() ); + std::vector ns; + auto c = cycle(ns); + std::vector v(std::begin(c), std::end(c)); + REQUIRE(v.empty()); } TEST_CASE("cycle: binds to lvalues, moves rvalues", "[cycle]") { - itertest::BasicIterable bi{'x', 'y', 'z'}; - SECTION("binds to lvalues") { - cycle(bi); - REQUIRE_FALSE( bi.was_moved_from() ); - } - SECTION("moves rvalues") { - cycle(std::move(bi)); - REQUIRE( bi.was_moved_from() ); - } + itertest::BasicIterable bi{'x', 'y', 'z'}; + SECTION("binds to lvalues") { + cycle(bi); + REQUIRE_FALSE(bi.was_moved_from()); + } + SECTION("moves rvalues") { + cycle(std::move(bi)); + REQUIRE(bi.was_moved_from()); + } } -TEST_CASE("cycle: doesn't move or copy elements of iterable", - "[cycle]") { - constexpr itertest::SolidInt arr[] = {{6}, {7}, {8}}; - auto c = cycle(arr); - *std::begin(c); +TEST_CASE("cycle: doesn't move or copy elements of iterable", "[cycle]") { + constexpr itertest::SolidInt arr[] = {{6}, {7}, {8}}; + auto c = cycle(arr); + *std::begin(c); } TEST_CASE("cycle: iterator meets requirements", "[cycle]") { - std::string s{}; - auto c = cycle(s); - REQUIRE( itertest::IsIterator::value ); + std::string s{}; + auto c = cycle(s); + REQUIRE(itertest::IsIterator::value); } TEST_CASE("cycle: arrow works", "[cycle]") { - std::vector v = {"hello"}; - auto c = cycle(v); - auto it = std::begin(c); - REQUIRE( it->size() == 5 ); + std::vector v = {"hello"}; + auto c = cycle(v); + auto it = std::begin(c); + REQUIRE(it->size() == 5); +} + +template +using ImpT = decltype(cycle(std::declval())); +TEST_CASE("cycle: has correct ctor and assign ops", "[cycle]") { + REQUIRE(itertest::IsMoveConstructibleOnly>::value); + REQUIRE(itertest::IsMoveConstructibleOnly>::value); } From eecb116676b48708bd88b447d3f37fba500a381e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:22:56 -0700 Subject: [PATCH 1323/1866] tests dropwhile impl has move ctor only --- test/test_dropwhile.cpp | 117 +++++++++++++++++++++------------------- 1 file changed, 63 insertions(+), 54 deletions(-) diff --git a/test/test_dropwhile.cpp b/test/test_dropwhile.cpp index c0b1707d..a05e1048 100644 --- a/test/test_dropwhile.cpp +++ b/test/test_dropwhile.cpp @@ -13,87 +13,96 @@ using iter::dropwhile; using Vec = const std::vector; TEST_CASE("dropwhile: skips initial elements", "[dropwhile]") { - Vec ns{1,2,3,4,5,6,7,8}; - auto d = dropwhile([](int i){return i < 5; }, ns); - Vec v(std::begin(d), std::end(d)); - Vec vc = {5,6,7,8}; - REQUIRE( v == vc ); + Vec ns{1, 2, 3, 4, 5, 6, 7, 8}; + auto d = dropwhile([](int i) { return i < 5; }, ns); + Vec v(std::begin(d), std::end(d)); + Vec vc = {5, 6, 7, 8}; + REQUIRE(v == vc); } TEST_CASE("dropwhile: doesn't skip anything if it shouldn't", "[dropwhile]") { - Vec ns {3,4,5,6}; - auto d = dropwhile([](int i){return i < 3; }, ns); - Vec v(std::begin(d), std::end(d)); - Vec vc = {3,4,5,6}; - REQUIRE( v == vc ); + Vec ns{3, 4, 5, 6}; + auto d = dropwhile([](int i) { return i < 3; }, ns); + Vec v(std::begin(d), std::end(d)); + Vec vc = {3, 4, 5, 6}; + REQUIRE(v == vc); } TEST_CASE("dropwhile: skips all elements when all are true under predicate", - "[dropwhile]") { - Vec ns {3,4,5,6}; - auto d = dropwhile([](int i){return i != 0; }, ns); - REQUIRE( std::begin(d) == std::end(d) ); + "[dropwhile]") { + Vec ns{3, 4, 5, 6}; + auto d = dropwhile([](int i) { return i != 0; }, ns); + REQUIRE(std::begin(d) == std::end(d)); } TEST_CASE("dropwhile: empty case is empty", "[dropwhile]") { - Vec ns{}; - auto d = dropwhile([](int i){return i != 0; }, ns); - REQUIRE( std::begin(d) == std::end(d) ); + Vec ns{}; + auto d = dropwhile([](int i) { return i != 0; }, ns); + REQUIRE(std::begin(d) == std::end(d)); } TEST_CASE("dropwhile: only drops from beginning", "[dropwhile]") { - Vec ns {1,2,3,4,5,6,5,4,3,2,1}; - auto d = dropwhile([](int i){return i < 5; }, ns); - Vec v(std::begin(d), std::end(d)); - Vec vc = {5,6,5,4,3,2,1}; - REQUIRE( v == vc ); + Vec ns{1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1}; + auto d = dropwhile([](int i) { return i < 5; }, ns); + Vec v(std::begin(d), std::end(d)); + Vec vc = {5, 6, 5, 4, 3, 2, 1}; + REQUIRE(v == vc); } TEST_CASE("dropwhile: operator->", "[dropwhile]") { - std::vector vs = {"a", "ab", "abcdef", "abcdefghi"}; - auto d = dropwhile( - [](const std::string& str) { return str.size() < 3; }, vs); - auto it = std::begin(d); - REQUIRE( it->size() == 6 ); + std::vector vs = {"a", "ab", "abcdef", "abcdefghi"}; + auto d = dropwhile([](const std::string& str) { return str.size() < 3; }, vs); + auto it = std::begin(d); + REQUIRE(it->size() == 6); } namespace { - int less_than_five(int i) { - return i < 5; - } + int less_than_five(int i) { + return i < 5; + } } TEST_CASE("dropwhile: works with function pointer", "[dropwhile]") { - Vec ns{1,2,3,4,5,6,7,8}; - auto d = dropwhile(less_than_five, ns); - Vec v(std::begin(d), std::end(d)); - Vec vc = {5,6,7,8}; - REQUIRE( v == vc ); + Vec ns{1, 2, 3, 4, 5, 6, 7, 8}; + auto d = dropwhile(less_than_five, ns); + Vec v(std::begin(d), std::end(d)); + Vec vc = {5, 6, 7, 8}; + REQUIRE(v == vc); } TEST_CASE("dropwhile: binds to lvalues, moves rvalues", "[dropwhile]") { - itertest::BasicIterable bi{1,2,3,4}; - SECTION("binds to lvalues") { - dropwhile(less_than_five, bi); - REQUIRE_FALSE( bi.was_moved_from() ); - } - SECTION("moves rvalues") { - dropwhile(less_than_five, std::move(bi)); - REQUIRE( bi.was_moved_from() ); - } + itertest::BasicIterable bi{1, 2, 3, 4}; + SECTION("binds to lvalues") { + dropwhile(less_than_five, bi); + REQUIRE_FALSE(bi.was_moved_from()); + } + SECTION("moves rvalues") { + dropwhile(less_than_five, std::move(bi)); + REQUIRE(bi.was_moved_from()); + } } -TEST_CASE("dropwhile: doesn't move or copy elements of iterable", - "[dropwhile]") { - constexpr itertest::SolidInt arr[] = {{6}, {7}, {8}}; - for (auto&& i : dropwhile( - [](const itertest::SolidInt&){return false;} , arr)) { - (void)i; - } +TEST_CASE( + "dropwhile: doesn't move or copy elements of iterable", "[dropwhile]") { + constexpr itertest::SolidInt arr[] = {{6}, {7}, {8}}; + for (auto&& i : + dropwhile([](const itertest::SolidInt&) { return false; }, arr)) { + (void)i; + } } TEST_CASE("dropwhile: iterator meets requirements", "[dropwhile]") { - std::string s{}; - auto c = dropwhile([]{return true;}, s); - REQUIRE( itertest::IsIterator::value ); + std::string s{}; + auto c = dropwhile([] { return true; }, s); + REQUIRE(itertest::IsIterator::value); +} + +template +using ImpT = decltype(dropwhile(std::declval(), std::declval())); +TEST_CASE("dropwhile: has correct ctor and assign ops", "[dropwhile]") { + using T1 = ImpT; + auto lam = [](char) { return false; }; + using T2 = ImpT; + REQUIRE(itertest::IsMoveConstructibleOnly::value); + REQUIRE(itertest::IsMoveConstructibleOnly::value); } From 7ca3c7b15b51f9afc96906eec5ed710691197a09 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:23:13 -0700 Subject: [PATCH 1324/1866] tests enumerate impl has move ctor only --- test/test_enumerate.cpp | 139 +++++++++++++++++++++------------------- 1 file changed, 73 insertions(+), 66 deletions(-) diff --git a/test/test_enumerate.cpp b/test/test_enumerate.cpp index 6f25b3bd..778cce39 100644 --- a/test/test_enumerate.cpp +++ b/test/test_enumerate.cpp @@ -9,12 +9,12 @@ #include namespace Catch { -template -std::string toString( const std::pair& p) { + template + std::string toString(const std::pair& p) { std::ostringstream oss; oss << '{' << p.first << ", " << p.second << '}'; return oss.str(); -} + } } #include "catch.hpp" @@ -26,26 +26,26 @@ using itertest::BasicIterable; using itertest::SolidInt; TEST_CASE("Basic Functioning enumerate", "[enumerate]") { - std::string str = "abc"; - auto e = enumerate(str); - Vec v(std::begin(e), std::end(e)); - Vec vc{{0, 'a'}, {1, 'b'}, {2, 'c'}}; + std::string str = "abc"; + auto e = enumerate(str); + Vec v(std::begin(e), std::end(e)); + Vec vc{{0, 'a'}, {1, 'b'}, {2, 'c'}}; - REQUIRE( v == vc ); + REQUIRE(v == vc); } TEST_CASE("Empty enumerate", "[enumerate]") { - std::string emp{}; - auto e = enumerate(emp); - REQUIRE( std::begin(e) == std::end(e) ); + std::string emp{}; + auto e = enumerate(emp); + REQUIRE(std::begin(e) == std::end(e)); } TEST_CASE("Postfix ++ enumerate", "[enumerate]") { - std::string s{"amz"}; - auto e = enumerate(s); - auto it = std::begin(e); - it++; - REQUIRE( (*it).first == 1 ); + std::string s{"amz"}; + auto e = enumerate(s); + auto it = std::begin(e); + it++; + REQUIRE((*it).first == 1); } TEST_CASE("enumerate: with starting value", "[enumerate]") { @@ -54,85 +54,92 @@ TEST_CASE("enumerate: with starting value", "[enumerate]") { Vec v(std::begin(e), std::end(e)); Vec vc{{5, 'h'}, {6, 'e'}, {7, 'y'}}; - REQUIRE( v == vc ); + REQUIRE(v == vc); } TEST_CASE("Modifications through enumerate affect container", "[enumerate]") { - std::vector v{1, 2, 3, 4}; - std::vector vc(v.size(), -1); - for (auto&& p : enumerate(v)){ - p.second = -1; - } + std::vector v{1, 2, 3, 4}; + std::vector vc(v.size(), -1); + for (auto&& p : enumerate(v)) { + p.second = -1; + } - REQUIRE( v == vc ); + REQUIRE(v == vc); } TEST_CASE("enumerate with static array works", "[enumerate]") { - char arr[] = {'w', 'x', 'y'}; + char arr[] = {'w', 'x', 'y'}; - SECTION("Conversion to vector") { - auto e = enumerate(arr); - Vec v(std::begin(e), std::end(e)); - Vec vc{{0, 'w'}, {1, 'x'}, {2, 'y'}}; - REQUIRE( v == vc ); - } + SECTION("Conversion to vector") { + auto e = enumerate(arr); + Vec v(std::begin(e), std::end(e)); + Vec vc{{0, 'w'}, {1, 'x'}, {2, 'y'}}; + REQUIRE(v == vc); + } - SECTION("Modification through enumerate") { - for (auto&& p : enumerate(arr)) { - p.second = 'z'; - } - std::vector v(std::begin(arr), std::end(arr)); - decltype(v) vc(v.size(), 'z'); - REQUIRE( v == vc ); + SECTION("Modification through enumerate") { + for (auto&& p : enumerate(arr)) { + p.second = 'z'; } + std::vector v(std::begin(arr), std::end(arr)); + decltype(v) vc(v.size(), 'z'); + REQUIRE(v == vc); + } } TEST_CASE("initializer_list works", "[enumerate]") { - auto e = enumerate({'a', 'b', 'c'}); - Vec v(std::begin(e), std::end(e)); - Vec vc{{0, 'a'}, {1, 'b'}, {2, 'c'}}; - REQUIRE( v == vc ); + auto e = enumerate({'a', 'b', 'c'}); + Vec v(std::begin(e), std::end(e)); + Vec vc{{0, 'a'}, {1, 'b'}, {2, 'c'}}; + REQUIRE(v == vc); } TEST_CASE("binds reference when it should", "[enumerate]") { - BasicIterable bi{'x', 'y', 'z'}; - auto e = enumerate(bi); - (void)e; - REQUIRE_FALSE( bi.was_moved_from() ); + BasicIterable bi{'x', 'y', 'z'}; + auto e = enumerate(bi); + (void)e; + REQUIRE_FALSE(bi.was_moved_from()); } TEST_CASE("moves rvalues into enumerable object", "[enumerate]") { - BasicIterable bi{'x', 'y', 'z'}; - auto e = enumerate(std::move(bi)); - REQUIRE( bi.was_moved_from()); - (void)e; + BasicIterable bi{'x', 'y', 'z'}; + auto e = enumerate(std::move(bi)); + REQUIRE(bi.was_moved_from()); + (void)e; } TEST_CASE("enumerate: operator->", "[enumerate]") { - std::vector ns = {50, 60, 70}; - auto e = enumerate(ns); - auto it = std::begin(e); - REQUIRE( it->first == 0 ); - REQUIRE( it->second == 50 ); + std::vector ns = {50, 60, 70}; + auto e = enumerate(ns); + auto it = std::begin(e); + REQUIRE(it->first == 0); + REQUIRE(it->second == 50); } TEST_CASE("Works with const iterable", "[enumerate]") { - const std::string s{"ace"}; - auto e = enumerate(s); - Vec v(std::begin(e), std::end(e)); - Vec vc{{0, 'a'}, {1, 'c'}, {2, 'e'}}; - REQUIRE( v == vc ); + const std::string s{"ace"}; + auto e = enumerate(s); + Vec v(std::begin(e), std::end(e)); + Vec vc{{0, 'a'}, {1, 'c'}, {2, 'e'}}; + REQUIRE(v == vc); } TEST_CASE("Doesn't move or copy elements of iterable", "[enumerate]") { - constexpr SolidInt arr[] = {{6}, {7}, {8}}; - for (auto&& i : enumerate(arr)) { - (void)i; - } + constexpr SolidInt arr[] = {{6}, {7}, {8}}; + for (auto&& i : enumerate(arr)) { + (void)i; + } } TEST_CASE("enumerate: iterator meets requirements", "[enumerate]") { - std::string s{}; - auto c = enumerate(s); - REQUIRE( itertest::IsIterator::value ); + std::string s{}; + auto c = enumerate(s); + REQUIRE(itertest::IsIterator::value); +} + +template +using ImpT = decltype(enumerate(std::declval())); +TEST_CASE("enumerate: has correct ctor and assign ops", "[enumerate]") { + REQUIRE(itertest::IsMoveConstructibleOnly>::value); + REQUIRE(itertest::IsMoveConstructibleOnly>::value); } From c2c99b65c4757dfc07e258afdcfbab3bd4857a4e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:23:25 -0700 Subject: [PATCH 1325/1866] tests filter impl has move ctor only --- test/test_filter.cpp | 164 +++++++++++++++++++++++-------------------- 1 file changed, 86 insertions(+), 78 deletions(-) diff --git a/test/test_filter.cpp b/test/test_filter.cpp index 650925f9..28ac6938 100644 --- a/test/test_filter.cpp +++ b/test/test_filter.cpp @@ -13,113 +13,121 @@ using iter::filter; using Vec = const std::vector; namespace { - bool less_than_five(int i) { - return i < 5; - } + bool less_than_five(int i) { + return i < 5; + } - class LessThanValue { - private: - int compare_val; + class LessThanValue { + private: + int compare_val; - public: - LessThanValue(int v) : compare_val(v) { } + public: + LessThanValue(int v) : compare_val(v) {} - bool operator() (int i) { - return i < this->compare_val; - } - }; + bool operator()(int i) { + return i < this->compare_val; + } + }; } TEST_CASE("filter: handles different functor types", "[filter]") { - Vec ns = {1,2, 5,6, 3,1, 7, -1, 5}; - Vec vc = {1,2,3,1,-1}; - SECTION("with function pointer") { - auto f = filter(less_than_five, ns); - Vec v(std::begin(f), std::end(f)); - REQUIRE( v == vc ); - } + Vec ns = {1, 2, 5, 6, 3, 1, 7, -1, 5}; + Vec vc = {1, 2, 3, 1, -1}; + SECTION("with function pointer") { + auto f = filter(less_than_five, ns); + Vec v(std::begin(f), std::end(f)); + REQUIRE(v == vc); + } - SECTION("with callable object") { - auto f = filter(LessThanValue{5}, ns); - Vec v(std::begin(f), std::end(f)); - REQUIRE( v == vc ); - } + SECTION("with callable object") { + auto f = filter(LessThanValue{5}, ns); + Vec v(std::begin(f), std::end(f)); + REQUIRE(v == vc); + } - SECTION("with lambda") { - auto ltf = [](int i) {return i < 5;}; - auto f = filter(ltf, ns); - Vec v(std::begin(f), std::end(f)); - REQUIRE( v == vc ); - } + SECTION("with lambda") { + auto ltf = [](int i) { return i < 5; }; + auto f = filter(ltf, ns); + Vec v(std::begin(f), std::end(f)); + REQUIRE(v == vc); + } } TEST_CASE("filter: iterator with lambda can be assigned", "[filter]") { - Vec ns{}; - auto ltf = [](int i) {return i < 5;}; - auto f = filter(ltf, ns); - auto it = std::begin(f); - it = std::begin(f); + Vec ns{}; + auto ltf = [](int i) { return i < 5; }; + auto f = filter(ltf, ns); + auto it = std::begin(f); + it = std::begin(f); } TEST_CASE("filter: using identity", "[filter]") { - Vec ns{0, 1, 2, 0, 3, 0, 0, 0, 4, 5, 0}; - auto f = filter(ns); - Vec v(std::begin(f), std::end(f)); + Vec ns{0, 1, 2, 0, 3, 0, 0, 0, 4, 5, 0}; + auto f = filter(ns); + Vec v(std::begin(f), std::end(f)); - Vec vc = {1,2,3,4,5}; - REQUIRE( v == vc ); + Vec vc = {1, 2, 3, 4, 5}; + REQUIRE(v == vc); } TEST_CASE("filter: binds to lvalues, moves rvales", "[filter]") { - itertest::BasicIterable bi{1,2,3,4}; - - SECTION("one-arg binds to lvalues") { - filter(bi); - REQUIRE_FALSE(bi.was_moved_from()); - } - - SECTION("two-arg binds to lvalues") { - filter(less_than_five, bi); - REQUIRE_FALSE(bi.was_moved_from()); - } - - SECTION("one-arg moves rvalues") { - filter(std::move(bi)); - REQUIRE(bi.was_moved_from()); - } - - SECTION("two-arg moves rvalues") { - filter(less_than_five, std::move(bi)); - REQUIRE(bi.was_moved_from()); - } + itertest::BasicIterable bi{1, 2, 3, 4}; + + SECTION("one-arg binds to lvalues") { + filter(bi); + REQUIRE_FALSE(bi.was_moved_from()); + } + + SECTION("two-arg binds to lvalues") { + filter(less_than_five, bi); + REQUIRE_FALSE(bi.was_moved_from()); + } + + SECTION("one-arg moves rvalues") { + filter(std::move(bi)); + REQUIRE(bi.was_moved_from()); + } + + SECTION("two-arg moves rvalues") { + filter(less_than_five, std::move(bi)); + REQUIRE(bi.was_moved_from()); + } } - TEST_CASE("filter: operator->", "[filter]") { - std::vector vs = {"ab", "abc", "abcdef"}; - auto f = filter([](const std::string& str) {return str.size() > 4;}, vs); - auto it = std::begin(f); - REQUIRE( it->size() == 6 ); + std::vector vs = {"ab", "abc", "abcdef"}; + auto f = filter([](const std::string& str) { return str.size() > 4; }, vs); + auto it = std::begin(f); + REQUIRE(it->size() == 6); } - TEST_CASE("filter: all elements fail predicate", "[filter]") { - Vec ns{10,20,30,40,50}; - auto f = filter(less_than_five, ns); + Vec ns{10, 20, 30, 40, 50}; + auto f = filter(less_than_five, ns); - REQUIRE( std::begin(f) == std::end(f) ); + REQUIRE(std::begin(f) == std::end(f)); } TEST_CASE("filter: doesn't move or copy elements of iterable", "[filter]") { - constexpr itertest::SolidInt arr[] = {{1}, {0}, {2}}; - for (auto&& i : filter( - [](const itertest::SolidInt& si) {return si.getint();},arr)) { - (void)i; - } + constexpr itertest::SolidInt arr[] = {{1}, {0}, {2}}; + for (auto&& i : + filter([](const itertest::SolidInt& si) { return si.getint(); }, arr)) { + (void)i; + } } TEST_CASE("filter: iterator meets requirements", "[filter]") { - std::string s{}; - auto c = filter([]{return true;}, s); - REQUIRE( itertest::IsIterator::value ); + std::string s{}; + auto c = filter([] { return true; }, s); + REQUIRE(itertest::IsIterator::value); +} + +template +using ImpT = decltype(filter(std::declval(), std::declval())); +TEST_CASE("filter: has correct ctor and assign ops", "[filter]") { + using T1 = ImpT; + auto lam = [](char) { return false; }; + using T2 = ImpT; + REQUIRE(itertest::IsMoveConstructibleOnly::value); + REQUIRE(itertest::IsMoveConstructibleOnly::value); } From ab005ea7c2a1769d2a1c948defe1d13bf66cd8d0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:23:37 -0700 Subject: [PATCH 1326/1866] tests filterfalse impl has move ctor only --- test/test_filterfalse.cpp | 134 ++++++++++++++++++++------------------ 1 file changed, 72 insertions(+), 62 deletions(-) diff --git a/test/test_filterfalse.cpp b/test/test_filterfalse.cpp index cb09d897..2116b30f 100644 --- a/test/test_filterfalse.cpp +++ b/test/test_filterfalse.cpp @@ -13,88 +13,98 @@ using iter::filterfalse; using Vec = const std::vector; namespace { - bool less_than_five(int i) { - return i < 5; - } + bool less_than_five(int i) { + return i < 5; + } - class LessThanValue { - private: - int compare_val; + class LessThanValue { + private: + int compare_val; - public: - LessThanValue(int v) : compare_val(v) { } + public: + LessThanValue(int v) : compare_val(v) {} - bool operator() (int i) { - return i < this->compare_val; - } - }; + bool operator()(int i) { + return i < this->compare_val; + } + }; } TEST_CASE("filterfalse: handles different functor types", "[filterfalse]") { - Vec ns = {1,2, 5,6, 3,1, 7, -1, 5}; - Vec vc = {5,6,7,5}; - SECTION("with function pointer") { - auto f = filterfalse(less_than_five, ns); - Vec v(std::begin(f), std::end(f)); - REQUIRE( v == vc ); - } + Vec ns = {1, 2, 5, 6, 3, 1, 7, -1, 5}; + Vec vc = {5, 6, 7, 5}; + SECTION("with function pointer") { + auto f = filterfalse(less_than_five, ns); + Vec v(std::begin(f), std::end(f)); + REQUIRE(v == vc); + } - SECTION("with callable object") { - auto f = filterfalse(LessThanValue{5}, ns); - Vec v(std::begin(f), std::end(f)); - REQUIRE( v == vc ); - } + SECTION("with callable object") { + auto f = filterfalse(LessThanValue{5}, ns); + Vec v(std::begin(f), std::end(f)); + REQUIRE(v == vc); + } - SECTION("with lambda") { - auto ltf = [](int i) {return i < 5;}; - auto f = filterfalse(ltf, ns); - Vec v(std::begin(f), std::end(f)); - REQUIRE( v == vc ); - } + SECTION("with lambda") { + auto ltf = [](int i) { return i < 5; }; + auto f = filterfalse(ltf, ns); + Vec v(std::begin(f), std::end(f)); + REQUIRE(v == vc); + } } TEST_CASE("filterfalse: using identity", "[filterfalse]") { - Vec ns{0, 1, 2, 0, 3, 0, 0, 0, 4, 5, 0}; - auto f = filterfalse(ns); - Vec v(std::begin(f), std::end(f)); + Vec ns{0, 1, 2, 0, 3, 0, 0, 0, 4, 5, 0}; + auto f = filterfalse(ns); + Vec v(std::begin(f), std::end(f)); - Vec vc = {0, 0, 0, 0, 0, 0}; - REQUIRE( v == vc ); + Vec vc = {0, 0, 0, 0, 0, 0}; + REQUIRE(v == vc); } TEST_CASE("filterfalse: binds to lvalues, moves rvales", "[filterfalse]") { - itertest::BasicIterable bi{1,2,3,4}; - - SECTION("one-arg binds to lvalues") { - filterfalse(bi); - REQUIRE_FALSE(bi.was_moved_from()); - } - - SECTION("two-arg binds to lvalues") { - filterfalse(less_than_five, bi); - REQUIRE_FALSE(bi.was_moved_from()); - } - - SECTION("one-arg moves rvalues") { - filterfalse(std::move(bi)); - REQUIRE(bi.was_moved_from()); - } - - SECTION("two-arg moves rvalues") { - filterfalse(less_than_five, std::move(bi)); - REQUIRE(bi.was_moved_from()); - } + itertest::BasicIterable bi{1, 2, 3, 4}; + + SECTION("one-arg binds to lvalues") { + filterfalse(bi); + REQUIRE_FALSE(bi.was_moved_from()); + } + + SECTION("two-arg binds to lvalues") { + filterfalse(less_than_five, bi); + REQUIRE_FALSE(bi.was_moved_from()); + } + + SECTION("one-arg moves rvalues") { + filterfalse(std::move(bi)); + REQUIRE(bi.was_moved_from()); + } + + SECTION("two-arg moves rvalues") { + filterfalse(less_than_five, std::move(bi)); + REQUIRE(bi.was_moved_from()); + } } TEST_CASE("filterfalse: all elements pass predicate", "[filterfalse]") { - Vec ns{0,1,2,3,4}; - auto f = filterfalse(less_than_five, ns); + Vec ns{0, 1, 2, 3, 4}; + auto f = filterfalse(less_than_five, ns); - REQUIRE( std::begin(f) == std::end(f) ); + REQUIRE(std::begin(f) == std::end(f)); } TEST_CASE("filterfalse: iterator meets requirements", "[filterfalse]") { - std::string s{}; - auto c = filterfalse([]{return true;}, s); - REQUIRE( itertest::IsIterator::value ); + std::string s{}; + auto c = filterfalse([] { return true; }, s); + REQUIRE(itertest::IsIterator::value); +} + +template +using ImpT = decltype(filterfalse(std::declval(), std::declval())); +TEST_CASE("filterfalse: has correct ctor and assign ops", "[filterfalse]") { + using T1 = ImpT; + auto lam = [](char) { return false; }; + using T2 = ImpT; + REQUIRE(itertest::IsMoveConstructibleOnly::value); + REQUIRE(itertest::IsMoveConstructibleOnly::value); } From 5078624588c8dc5c9992e7cf8a72cd7accae0ce4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:23:46 -0700 Subject: [PATCH 1327/1866] tests groupby impl has move ctor only --- test/test_groupby.cpp | 298 +++++++++++++++++++++--------------------- 1 file changed, 146 insertions(+), 152 deletions(-) diff --git a/test/test_groupby.cpp b/test/test_groupby.cpp index ad74be9d..1bbc7864 100644 --- a/test/test_groupby.cpp +++ b/test/test_groupby.cpp @@ -11,210 +11,204 @@ using iter::groupby; namespace { - int length(const std::string& s) { - return s.size(); + int length(const std::string& s) { + return s.size(); + } + + struct Sizer { + int operator()(const std::string& s) { + return s.size(); } + }; - struct Sizer { - int operator()(const std::string& s) { - return s.size(); - } - }; - - const std::vector vec = { - "hi", "ab", "ho", - "abc", "def", - "abcde", "efghi" - }; + const std::vector vec = { + "hi", "ab", "ho", "abc", "def", "abcde", "efghi"}; } TEST_CASE("groupby: works with lambda, callable, and function pointer") { - std::vector keys; - std::vector> groups; - - SECTION("Function pointer") { - for (auto&& gb : groupby(vec, length)) { - keys.push_back(gb.first); - groups.emplace_back(std::begin(gb.second), std::end(gb.second)); - } + std::vector keys; + std::vector> groups; + + SECTION("Function pointer") { + for (auto&& gb : groupby(vec, length)) { + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); } + } - SECTION("Callable object") { - for (auto&& gb : groupby(vec, Sizer{})) { - keys.push_back(gb.first); - groups.emplace_back(std::begin(gb.second), std::end(gb.second)); - } + SECTION("Callable object") { + for (auto&& gb : groupby(vec, Sizer{})) { + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); } + } - SECTION("lambda function") { - for (auto&& gb : groupby(vec, - [](const std::string& s){return s.size();})) { - keys.push_back(gb.first); - groups.emplace_back(std::begin(gb.second), std::end(gb.second)); - } + SECTION("lambda function") { + for (auto&& gb : + groupby(vec, [](const std::string& s) { return s.size(); })) { + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); } + } - const std::vector kc = {2, 3, 5}; - REQUIRE( keys == kc ); + const std::vector kc = {2, 3, 5}; + REQUIRE(keys == kc); - const std::vector> gc = { - {"hi", "ab", "ho"}, - {"abc", "def"}, - {"abcde", "efghi"}, - }; + const std::vector> gc = { + {"hi", "ab", "ho"}, {"abc", "def"}, {"abcde", "efghi"}, + }; - REQUIRE( groups == gc ); + REQUIRE(groups == gc); } TEST_CASE("groupby: groups can be skipped completely", "[groupby]") { - std::vector keys; - std::vector> groups; - for (auto&& gb : groupby(vec, &length)) { - if (gb.first == 3) { - continue; - } - keys.push_back(gb.first); - groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + std::vector keys; + std::vector> groups; + for (auto&& gb : groupby(vec, &length)) { + if (gb.first == 3) { + continue; } + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + } - const std::vector kc = {2, 5}; - REQUIRE( keys == kc ); + const std::vector kc = {2, 5}; + REQUIRE(keys == kc); - const std::vector> gc = { - {"hi", "ab", "ho"}, - {"abcde", "efghi"}, - }; + const std::vector> gc = { + {"hi", "ab", "ho"}, {"abcde", "efghi"}, + }; - REQUIRE( groups == gc ); + REQUIRE(groups == gc); } TEST_CASE("groupby: groups can be skipped partially", "[groupby]") { - std::vector keys; - std::vector> groups; - for (auto&& gb : groupby(vec, &length)) { - keys.push_back(gb.first); - if (gb.first == 3) { - std::vector cut_short = {*std::begin(gb.second)}; - groups.push_back(cut_short); - } else { - groups.emplace_back(std::begin(gb.second), std::end(gb.second)); - } + std::vector keys; + std::vector> groups; + for (auto&& gb : groupby(vec, &length)) { + keys.push_back(gb.first); + if (gb.first == 3) { + std::vector cut_short = {*std::begin(gb.second)}; + groups.push_back(cut_short); + } else { + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); } + } - const std::vector kc = {2, 3, 5}; - REQUIRE( keys == kc ); + const std::vector kc = {2, 3, 5}; + REQUIRE(keys == kc); - const std::vector> gc = { - {"hi", "ab", "ho"}, - {"abc"}, - {"abcde", "efghi"}, - }; + const std::vector> gc = { + {"hi", "ab", "ho"}, {"abc"}, {"abcde", "efghi"}, + }; - REQUIRE( groups == gc ); + REQUIRE(groups == gc); } TEST_CASE("groupby: single argument uses elements as keys", "[groupby]") { - std::vector ivec = {5, 5, 6, 6, 19, 19, 19, 19, 69, 0, 10, 10}; - std::vector keys; - std::vector> groups; - for (auto&& gb : groupby(ivec)) { - keys.push_back(gb.first); - groups.emplace_back(std::begin(gb.second), std::end(gb.second)); - } - - const std::vector kc = {5, 6, 19, 69, 0, 10}; - REQUIRE( keys == kc ); - - std::vector> gc = { - {5, 5}, - {6, 6}, - {19, 19, 19, 19}, - {69}, - {0}, - {10, 10}, - }; - - REQUIRE( groups == gc ); + std::vector ivec = {5, 5, 6, 6, 19, 19, 19, 19, 69, 0, 10, 10}; + std::vector keys; + std::vector> groups; + for (auto&& gb : groupby(ivec)) { + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + } + + const std::vector kc = {5, 6, 19, 69, 0, 10}; + REQUIRE(keys == kc); + + std::vector> gc = { + {5, 5}, {6, 6}, {19, 19, 19, 19}, {69}, {0}, {10, 10}, + }; + + REQUIRE(groups == gc); } TEST_CASE("groupby: empty iterable yields nothing", "[groupby]") { - std::vector ivec{}; - auto g = groupby(ivec); - REQUIRE( std::begin(g) == std::end(g) ); + std::vector ivec{}; + auto g = groupby(ivec); + REQUIRE(std::begin(g) == std::end(g)); } TEST_CASE("groupby: inner iterator (group) not used", "[groupby]") { - std::vector keys; - for (auto&& gb : groupby(vec, length)) { - keys.push_back(gb.first); - } - - std::vector kc = {2, 3, 5}; - REQUIRE( keys == kc ); + std::vector keys; + for (auto&& gb : groupby(vec, length)) { + keys.push_back(gb.first); + } + + std::vector kc = {2, 3, 5}; + REQUIRE(keys == kc); } TEST_CASE("groupby: doesn't double dereference", "[groupby]") { - itertest::InputIterable seq; - for (auto&& kg : groupby(seq, [](int i){return i < 3;})) { - for (auto&& e : kg.second) { - (void)e; - } + itertest::InputIterable seq; + for (auto&& kg : groupby(seq, [](int i) { return i < 3; })) { + for (auto&& e : kg.second) { + (void)e; } + } } TEST_CASE("grouby: iterator doesn't need to be dereferenced before advanced", - "[groupby]") { - std::vector ns = {2, 4, 7}; - auto g = groupby(ns); - auto it = std::begin(g); - ++it; - REQUIRE( (*it).first == 4 ); + "[groupby]") { + std::vector ns = {2, 4, 7}; + auto g = groupby(ns); + auto it = std::begin(g); + ++it; + REQUIRE((*it).first == 4); } -TEST_CASE("groupby: iterator can be dereferenced multiple times", "[groupby]"){ - std::vector ns = {2, 4, 7}; - auto g = groupby(ns); - auto it = std::begin(g); - auto k1 = (*it).first; - auto k2 = (*it).first; - REQUIRE( k1 == k2 ); +TEST_CASE("groupby: iterator can be dereferenced multiple times", "[groupby]") { + std::vector ns = {2, 4, 7}; + auto g = groupby(ns); + auto it = std::begin(g); + auto k1 = (*it).first; + auto k2 = (*it).first; + REQUIRE(k1 == k2); } - -TEST_CASE("groupby: copy constructed iterators behave as expected", - "[groupby]") { - std::vector ns = {2, 3, 4, 5}; - auto g = groupby(ns); - auto it = std::begin(g); - REQUIRE( it->first == 2 ); - { - auto it2 = it; - REQUIRE( it2->first == 2); - ++it; - REQUIRE( it->first == 3 ); - REQUIRE( *std::begin(it->second) == 3 ); - } - REQUIRE( it->first == 3 ); - REQUIRE( *std::begin(it->second) == 3 ); +TEST_CASE( + "groupby: copy constructed iterators behave as expected", "[groupby]") { + std::vector ns = {2, 3, 4, 5}; + auto g = groupby(ns); + auto it = std::begin(g); + REQUIRE(it->first == 2); + { + auto it2 = it; + REQUIRE(it2->first == 2); + ++it; + REQUIRE(it->first == 3); + REQUIRE(*std::begin(it->second) == 3); + } + REQUIRE(it->first == 3); + REQUIRE(*std::begin(it->second) == 3); } - TEST_CASE("groupby: operator-> on both iterator types", "[groupby]") { - std::vector ns = {"a", "abc"}; - auto g = groupby(ns, [](const std::string& str){return str.size();}); - auto it = std::begin(g); - REQUIRE( it->first == 1 ); - auto it2 = std::begin(it->second); - REQUIRE( it2->size() == 1 ); + std::vector ns = {"a", "abc"}; + auto g = groupby(ns, [](const std::string& str) { return str.size(); }); + auto it = std::begin(g); + REQUIRE(it->first == 1); + auto it2 = std::begin(it->second); + REQUIRE(it2->size() == 1); } TEST_CASE("groupby: iterator and groupiterator are correct", "[groupby]") { - std::string s{"abc"}; - auto c = groupby(s); - auto it = std::begin(c); - REQUIRE( itertest::IsIterator::value ); - auto&& gp = (*it).second; - auto it2 = std::begin(gp); - REQUIRE( itertest::IsIterator::value ); + std::string s{"abc"}; + auto c = groupby(s); + auto it = std::begin(c); + REQUIRE(itertest::IsIterator::value); + auto&& gp = (*it).second; + auto it2 = std::begin(gp); + REQUIRE(itertest::IsIterator::value); +} +template +using ImpT = decltype(groupby(std::declval(), std::declval())); +TEST_CASE("groupby: has correct ctor and assign ops", "[groupby]") { + using T1 = ImpT; + auto lam = [](char) { return false; }; + using T2 = ImpT; + REQUIRE(itertest::IsMoveConstructibleOnly::value); + REQUIRE(itertest::IsMoveConstructibleOnly::value); } From 2afd601714577bc900a2a1f6d9865b1a8df4e10a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:23:58 -0700 Subject: [PATCH 1328/1866] tests imap impl has move ctor only --- test/test_imap.cpp | 198 +++++++++++++++++++++++---------------------- 1 file changed, 103 insertions(+), 95 deletions(-) diff --git a/test/test_imap.cpp b/test/test_imap.cpp index 6911c0fa..634bc6c8 100644 --- a/test/test_imap.cpp +++ b/test/test_imap.cpp @@ -12,133 +12,141 @@ using iter::imap; using Vec = const std::vector; namespace { - int plusone(int i) { - return i + 1; + int plusone(int i) { + return i + 1; + } + + class PlusOner { + public: + int operator()(int i) { + return i + 1; } + }; - class PlusOner { - public: - int operator()(int i) { - return i + 1; - } - }; - - int power(int b, int e) { - int acc = 1; - for (int i = 0; i < e; ++i) { - acc *= b; - } - return acc; + int power(int b, int e) { + int acc = 1; + for (int i = 0; i < e; ++i) { + acc *= b; } + return acc; + } } TEST_CASE("imap: works with lambda, callable, and function", "[imap]") { - Vec ns = {10, 20, 30}; - SECTION("with lambda") { - auto im = imap([](int i) { return i + 1; }, ns); - Vec v(std::begin(im), std::end(im)); - Vec vc = {11, 21, 31}; - REQUIRE( v == vc ); - } - - SECTION("with function") { - auto im = imap(plusone, ns); - Vec v(std::begin(im), std::end(im)); - Vec vc = {11, 21, 31}; - REQUIRE( v == vc ); - } + Vec ns = {10, 20, 30}; + SECTION("with lambda") { + auto im = imap([](int i) { return i + 1; }, ns); + Vec v(std::begin(im), std::end(im)); + Vec vc = {11, 21, 31}; + REQUIRE(v == vc); + } - SECTION("with function") { - auto im = imap(PlusOner{}, ns); - Vec v(std::begin(im), std::end(im)); - Vec vc = {11, 21, 31}; - REQUIRE( v == vc ); - } + SECTION("with function") { + auto im = imap(plusone, ns); + Vec v(std::begin(im), std::end(im)); + Vec vc = {11, 21, 31}; + REQUIRE(v == vc); + } + SECTION("with function") { + auto im = imap(PlusOner{}, ns); + Vec v(std::begin(im), std::end(im)); + Vec vc = {11, 21, 31}; + REQUIRE(v == vc); + } } TEST_CASE("imap: works with multiple sequences", "[imap]") { - Vec bases = {0, 1, 2, 3}; - Vec exps = {1, 2, 3, 4}; + Vec bases = {0, 1, 2, 3}; + Vec exps = {1, 2, 3, 4}; - auto im = imap(power, bases, exps); - Vec v(std::begin(im), std::end(im)); - Vec vc = {0, 1, 8, 81}; + auto im = imap(power, bases, exps); + Vec v(std::begin(im), std::end(im)); + Vec vc = {0, 1, 8, 81}; - REQUIRE( v == vc ); + REQUIRE(v == vc); } TEST_CASE("imap: terminates on shortest squence", "[imap]") { - Vec ns1 = {1, 2, 3, 4}; - Vec ns2 = {2, 4, 6, 8, 10}; - Vec vc = {3, 6, 9, 12}; - SECTION("shortest sequence first") { - auto im = imap([](int a, int b){ return a + b; }, ns1, ns2); - Vec v(std::begin(im), std::end(im)); - REQUIRE( v == vc ); - } - SECTION("shortest sequence second") { - auto im = imap([](int a, int b){ return a + b; }, ns2, ns1); - Vec v(std::begin(im), std::end(im)); - REQUIRE( v == vc ); - } + Vec ns1 = {1, 2, 3, 4}; + Vec ns2 = {2, 4, 6, 8, 10}; + Vec vc = {3, 6, 9, 12}; + SECTION("shortest sequence first") { + auto im = imap([](int a, int b) { return a + b; }, ns1, ns2); + Vec v(std::begin(im), std::end(im)); + REQUIRE(v == vc); + } + SECTION("shortest sequence second") { + auto im = imap([](int a, int b) { return a + b; }, ns2, ns1); + Vec v(std::begin(im), std::end(im)); + REQUIRE(v == vc); + } } TEST_CASE("imap: operator->", "[imap]") { - std::vector vs = {"ab", "abcd", "abcdefg"}; - { - auto m = imap([](std::string& s) { return s; }, vs); - auto it = std::begin(m); - REQUIRE( it->size() == 2 ); - } - - { - auto m = imap([](std::string& s) -> std::string& { return s; }, vs); - auto it = std::begin(m); - REQUIRE( it->size() == 2 ); - } + std::vector vs = {"ab", "abcd", "abcdefg"}; + { + auto m = imap([](std::string& s) { return s; }, vs); + auto it = std::begin(m); + REQUIRE(it->size() == 2); + } + + { + auto m = imap([](std::string& s) -> std::string& { return s; }, vs); + auto it = std::begin(m); + REQUIRE(it->size() == 2); + } } - TEST_CASE("imap: empty sequence gives nothing", "[imap]") { - Vec v{}; - auto im = imap(plusone, v); - REQUIRE( std::begin(im) == std::end(im) ); + Vec v{}; + auto im = imap(plusone, v); + REQUIRE(std::begin(im) == std::end(im)); } TEST_CASE("imap: binds to lvalues, moves rvalues", "[imap]") { - itertest::BasicIterable bi{1, 2}; - SECTION("binds to lvalues") { - imap(plusone, bi); - REQUIRE_FALSE(bi.was_moved_from()); - } - - SECTION("moves rvalues") { - imap(plusone, std::move(bi)); - REQUIRE(bi.was_moved_from()); - } + itertest::BasicIterable bi{1, 2}; + SECTION("binds to lvalues") { + imap(plusone, bi); + REQUIRE_FALSE(bi.was_moved_from()); + } + + SECTION("moves rvalues") { + imap(plusone, std::move(bi)); + REQUIRE(bi.was_moved_from()); + } } TEST_CASE("imap: doesn't move or copy elements of iterable", "[imap]") { - constexpr itertest::SolidInt arr[] = {{1}, {0}, {2}}; - for (auto&& i : imap([](const itertest::SolidInt& si){return si.getint();}, - arr)) { - (void)i; - } + constexpr itertest::SolidInt arr[] = {{1}, {0}, {2}}; + for (auto&& i : + imap([](const itertest::SolidInt& si) { return si.getint(); }, arr)) { + (void)i; + } } TEST_CASE("imap: postfix ++", "[imap]") { - Vec ns = {10, 20}; - auto im = imap(plusone, ns); - auto it = std::begin(im); - it++; - REQUIRE( (*it) == 21 ); - it++; - REQUIRE( it == std::end(im) ); + Vec ns = {10, 20}; + auto im = imap(plusone, ns); + auto it = std::begin(im); + it++; + REQUIRE((*it) == 21); + it++; + REQUIRE(it == std::end(im)); } TEST_CASE("imap: iterator meets requirements", "[imap]") { - std::string s{}; - auto c = imap([](char){return 1;}, s); - REQUIRE( itertest::IsIterator::value ); + std::string s{}; + auto c = imap([](char) { return 1; }, s); + REQUIRE(itertest::IsIterator::value); +} + +template +using ImpT = decltype(imap(std::declval(), std::declval())); +TEST_CASE("imap: has correct ctor and assign ops", "[imap]") { + using T1 = ImpT; + auto lam = [](char) { return false; }; + using T2 = ImpT; + REQUIRE(itertest::IsMoveConstructibleOnly::value); + REQUIRE(itertest::IsMoveConstructibleOnly::value); } From c0bf33235145b89c390bc80bb22389fc8fbc23c6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:24:11 -0700 Subject: [PATCH 1329/1866] tests permutations impl has move ctor only --- test/test_permutations.cpp | 116 +++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 55 deletions(-) diff --git a/test/test_permutations.cpp b/test/test_permutations.cpp index 2e012131..68fa24f9 100644 --- a/test/test_permutations.cpp +++ b/test/test_permutations.cpp @@ -12,79 +12,85 @@ using iter::permutations; using IntPermSet = std::multiset>; TEST_CASE("permutations: basic test, 3 element sequence", "[permutations]") { - const std::vector ns = {1, 7, 9}; - auto p = permutations(ns); + const std::vector ns = {1, 7, 9}; + auto p = permutations(ns); - IntPermSet v; - for (auto&& st : p) { - v.emplace(std::begin(st), std::end(st)); - } + IntPermSet v; + for (auto&& st : p) { + v.emplace(std::begin(st), std::end(st)); + } - const IntPermSet vc = - {{1, 7, 9}, {1, 9, 7}, {7, 1, 9}, {7, 9, 1}, {9, 1, 7}, {9, 7, 1}}; - REQUIRE( v == vc ); + const IntPermSet vc = { + {1, 7, 9}, {1, 9, 7}, {7, 1, 9}, {7, 9, 1}, {9, 1, 7}, {9, 7, 1}}; + REQUIRE(v == vc); } -TEST_CASE("permutations: empty sequence has one empy permutation", - "[permutations]") { - const std::vector ns{}; - auto p = permutations(ns); - auto it = std::begin(p); - REQUIRE( (*it).empty() ); - it++; - REQUIRE( it == std::end(p) ); +TEST_CASE( + "permutations: empty sequence has one empy permutation", "[permutations]") { + const std::vector ns{}; + auto p = permutations(ns); + auto it = std::begin(p); + REQUIRE((*it).empty()); + it++; + REQUIRE(it == std::end(p)); } TEST_CASE("permutations: iterators can be compared", "[permutations]") { - const std::vector ns = {1, 2}; - auto p = permutations(ns); - auto it = std::begin(p); - REQUIRE( it == std::begin(p) ); - REQUIRE_FALSE( it != std::begin(p) ); - REQUIRE( it != std::end(p) ); - REQUIRE_FALSE( it == std::end(p) ); - ++it; - REQUIRE_FALSE( it == std::begin(p) ); - REQUIRE( it != std::begin(p) ); - REQUIRE_FALSE( it == std::end(p) ); - REQUIRE( it != std::end(p) ); - ++it; - REQUIRE( it == std::end(p) ); - REQUIRE_FALSE( it != std::end(p) ); + const std::vector ns = {1, 2}; + auto p = permutations(ns); + auto it = std::begin(p); + REQUIRE(it == std::begin(p)); + REQUIRE_FALSE(it != std::begin(p)); + REQUIRE(it != std::end(p)); + REQUIRE_FALSE(it == std::end(p)); + ++it; + REQUIRE_FALSE(it == std::begin(p)); + REQUIRE(it != std::begin(p)); + REQUIRE_FALSE(it == std::end(p)); + REQUIRE(it != std::end(p)); + ++it; + REQUIRE(it == std::end(p)); + REQUIRE_FALSE(it != std::end(p)); } - TEST_CASE("permutations: binds to lvalues, moves rvalues", "[permutations]") { - itertest::BasicIterable bi{1, 2}; - SECTION("binds to lvalues") { - permutations(bi); - REQUIRE_FALSE(bi.was_moved_from()); - } + itertest::BasicIterable bi{1, 2}; + SECTION("binds to lvalues") { + permutations(bi); + REQUIRE_FALSE(bi.was_moved_from()); + } - SECTION("moves rvalues") { - permutations(std::move(bi)); - REQUIRE(bi.was_moved_from()); - } + SECTION("moves rvalues") { + permutations(std::move(bi)); + REQUIRE(bi.was_moved_from()); + } } namespace itertest { - bool operator<(const SolidInt& lhs, const SolidInt& rhs) { - return lhs.getint() < rhs.getint(); - } + bool operator<(const SolidInt& lhs, const SolidInt& rhs) { + return lhs.getint() < rhs.getint(); + } } TEST_CASE("permutations doesn't move or copy elements of iterable", - "[permutations]") { - constexpr itertest::SolidInt arr[] = {{1}, {0}, {2}}; - for (auto&& st : permutations(arr)) { - (void)st; - } + "[permutations]") { + constexpr itertest::SolidInt arr[] = {{1}, {0}, {2}}; + for (auto&& st : permutations(arr)) { + (void)st; + } } TEST_CASE("permutations: iterator meets requirements", "[permutations]") { - std::string s{"abc"}; - auto c = permutations(s); - REQUIRE( itertest::IsIterator::value ); - auto&& row = *std::begin(c); - REQUIRE( itertest::IsIterator::value ); + std::string s{"abc"}; + auto c = permutations(s); + REQUIRE(itertest::IsIterator::value); + auto&& row = *std::begin(c); + REQUIRE(itertest::IsIterator::value); +} + +template +using ImpT = decltype(permutations(std::declval())); +TEST_CASE("permutations: has correct ctor and assign ops", "[permutations]") { + REQUIRE(itertest::IsMoveConstructibleOnly>::value); + REQUIRE(itertest::IsMoveConstructibleOnly>::value); } From 31d3b8a3467898ab299708ab2a5555cfaff7bb9a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:24:23 -0700 Subject: [PATCH 1330/1866] tests powerset impl has move ctor only --- test/test_powerset.cpp | 157 +++++++++++++++++++++-------------------- 1 file changed, 82 insertions(+), 75 deletions(-) diff --git a/test/test_powerset.cpp b/test/test_powerset.cpp index 3c13e09f..fae08df8 100644 --- a/test/test_powerset.cpp +++ b/test/test_powerset.cpp @@ -12,98 +12,105 @@ using iter::powerset; using IntPermSet = std::multiset>; TEST_CASE("powerset: basic test, [1, 2, 3]", "[powerset]") { - const std::vector ns = {1, 2, 3}; - IntPermSet v; - for (auto&& st : powerset(ns)) { - v.emplace(std::begin(st), std::end(st)); - } - - const IntPermSet vc = { std::multiset{}, - {1}, {2}, {3,}, {1,2}, {1,3}, {2,3}, {1,2,3} }; - REQUIRE( v == vc ); + const std::vector ns = {1, 2, 3}; + IntPermSet v; + for (auto&& st : powerset(ns)) { + v.emplace(std::begin(st), std::end(st)); + } + + const IntPermSet vc = {std::multiset{}, {1}, {2}, + { + 3, + }, + {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}}; + REQUIRE(v == vc); } TEST_CASE("powerset: empty sequence gives only empty set", "[powerset]") { - const std::vector ns = {}; - auto ps = powerset(ns); - auto it = std::begin(ps); - REQUIRE( std::begin(*it) == std::end(*it) ); // it's empty - ++it; - REQUIRE( it == std::end(ps) ); + const std::vector ns = {}; + auto ps = powerset(ns); + auto it = std::begin(ps); + REQUIRE(std::begin(*it) == std::end(*it)); // it's empty + ++it; + REQUIRE(it == std::end(ps)); } TEST_CASE("powerset: iterators can be compared", "[powerset]") { - std::vector ns = {1, 2}; - auto p = powerset(ns); - { - auto it = std::begin(p); - REQUIRE( it == std::begin(p) ); - REQUIRE_FALSE( it != std::begin(p) ); - REQUIRE( it != std::end(p) ); - REQUIRE_FALSE( it == std::end(p) ); - ++it; - REQUIRE_FALSE( it == std::begin(p) ); - REQUIRE( it != std::begin(p) ); - REQUIRE_FALSE( it == std::end(p) ); - REQUIRE( it != std::end(p) ); - ++it; - ++it; - ++it; - REQUIRE( it == std::end(p) ); - } - - ns.push_back(3); - { - auto it = std::begin(p); - auto it2 = std::begin(p); - std::advance(it, 4); - std::advance(it2, 4); - REQUIRE( it == it2 ); - ++it2; - REQUIRE( it != it2 ); - } - -} + std::vector ns = {1, 2}; + auto p = powerset(ns); + { + auto it = std::begin(p); + REQUIRE(it == std::begin(p)); + REQUIRE_FALSE(it != std::begin(p)); + REQUIRE(it != std::end(p)); + REQUIRE_FALSE(it == std::end(p)); + ++it; + REQUIRE_FALSE(it == std::begin(p)); + REQUIRE(it != std::begin(p)); + REQUIRE_FALSE(it == std::end(p)); + REQUIRE(it != std::end(p)); + ++it; + ++it; + ++it; + REQUIRE(it == std::end(p)); + } -TEST_CASE("powerset: iterator copy ctor is correct", "[powerset]") { - // { {}, {1}, {2}, {1, 2} } - std::vector ns = {1, 2}; - auto p = powerset(ns); + ns.push_back(3); + { auto it = std::begin(p); - auto it2(it); - REQUIRE( it == it2 ); + auto it2 = std::begin(p); + std::advance(it, 4); + std::advance(it2, 4); + REQUIRE(it == it2); ++it2; - REQUIRE( it != it2 ); - REQUIRE( std::begin(*it) == std::end(*it) ); + REQUIRE(it != it2); + } } - +TEST_CASE("powerset: iterator copy ctor is correct", "[powerset]") { + // { {}, {1}, {2}, {1, 2} } + std::vector ns = {1, 2}; + auto p = powerset(ns); + auto it = std::begin(p); + auto it2(it); + REQUIRE(it == it2); + ++it2; + REQUIRE(it != it2); + REQUIRE(std::begin(*it) == std::end(*it)); +} TEST_CASE("powerset: binds to lvalues, moves rvalues", "[powerset]") { - itertest::BasicIterable bi{1, 2}; - SECTION("binds to lvalues") { - powerset(bi); - REQUIRE_FALSE(bi.was_moved_from()); - } - SECTION("moves rvalues") { - powerset(std::move(bi)); - REQUIRE(bi.was_moved_from()); - } + itertest::BasicIterable bi{1, 2}; + SECTION("binds to lvalues") { + powerset(bi); + REQUIRE_FALSE(bi.was_moved_from()); + } + SECTION("moves rvalues") { + powerset(std::move(bi)); + REQUIRE(bi.was_moved_from()); + } } -TEST_CASE("powerset: doesn't move or copy elements of iterable", "[powerset]"){ - constexpr itertest::SolidInt arr[] = {{1}, {0}, {2}}; - for (auto&& st : powerset(arr)) { - for (auto&& i : st) { - (void)i; - } +TEST_CASE("powerset: doesn't move or copy elements of iterable", "[powerset]") { + constexpr itertest::SolidInt arr[] = {{1}, {0}, {2}}; + for (auto&& st : powerset(arr)) { + for (auto&& i : st) { + (void)i; } + } } TEST_CASE("powerset: iterator meets requirements", "[powerset]") { - std::string s{"abc"}; - auto c = powerset(s); - REQUIRE( itertest::IsIterator::value ); - auto&& row = *std::begin(c); - REQUIRE( itertest::IsIterator::value ); + std::string s{"abc"}; + auto c = powerset(s); + REQUIRE(itertest::IsIterator::value); + auto&& row = *std::begin(c); + REQUIRE(itertest::IsIterator::value); +} + +template +using ImpT = decltype(powerset(std::declval())); +TEST_CASE("powerset: has correct ctor and assign ops", "[powerset]") { + REQUIRE(itertest::IsMoveConstructibleOnly>::value); + REQUIRE(itertest::IsMoveConstructibleOnly>::value); } From de7bd62bfa012fd9d31df8c16d5dde947cac9169 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:24:30 -0700 Subject: [PATCH 1331/1866] tests product impl has move ctor only --- test/test_product.cpp | 153 +++++++++++++++++++++--------------------- 1 file changed, 77 insertions(+), 76 deletions(-) diff --git a/test/test_product.cpp b/test/test_product.cpp index fb6ea0cc..d42cde31 100644 --- a/test/test_product.cpp +++ b/test/test_product.cpp @@ -12,110 +12,111 @@ using iter::product; using Vec = const std::vector; TEST_CASE("product: basic test, two sequences", "[product]") { - using TP = std::tuple; - using ResType = std::vector; + using TP = std::tuple; + using ResType = std::vector; - Vec n1 = {0, 1}; - const std::string s{"abc"}; + Vec n1 = {0, 1}; + const std::string s{"abc"}; - auto p = product(n1, s); - ResType v(std::begin(p), std::end(p)); - ResType vc = {TP{0,'a'}, TP{0,'b'}, TP{0,'c'}, - TP{1,'a'}, TP{1,'b'}, TP{1,'c'}}; + auto p = product(n1, s); + ResType v(std::begin(p), std::end(p)); + ResType vc = { + TP{0, 'a'}, TP{0, 'b'}, TP{0, 'c'}, TP{1, 'a'}, TP{1, 'b'}, TP{1, 'c'}}; - REQUIRE( v == vc ); + REQUIRE(v == vc); } TEST_CASE("product: three sequences", "[product]") { - using TP = std::tuple ; - using ResType = const std::vector; + using TP = std::tuple; + using ResType = const std::vector; - Vec n1 = {0, 1}; - const std::string s{"ab"}; - Vec n2 = {2}; + Vec n1 = {0, 1}; + const std::string s{"ab"}; + Vec n2 = {2}; - auto p = product(n1, s, n2); - ResType v(std::begin(p), std::end(p)); + auto p = product(n1, s, n2); + ResType v(std::begin(p), std::end(p)); - ResType vc = { - TP{0, 'a', 2}, - TP{0, 'b', 2}, - TP{1, 'a', 2}, - TP{1, 'b', 2} - }; + ResType vc = {TP{0, 'a', 2}, TP{0, 'b', 2}, TP{1, 'a', 2}, TP{1, 'b', 2}}; - REQUIRE( v == vc ); + REQUIRE(v == vc); } - TEST_CASE("product: empty when any iterable is empty", "[product]") { - Vec n1 = {0, 1}; - Vec n2 = {0, 1, 2}; - Vec emp = {}; - - SECTION("first iterable is empty") { - auto p = product(emp, n1, n2); - REQUIRE( std::begin(p) == std::end(p) ); - } - - SECTION("middle iterable is empty") { - auto p = product(n1, emp, n2); - REQUIRE( std::begin(p) == std::end(p) ); - } - - SECTION("last iterable is empty") { - auto p = product(n1, n2, emp); - REQUIRE( std::begin(p) == std::end(p) ); - } + Vec n1 = {0, 1}; + Vec n2 = {0, 1, 2}; + Vec emp = {}; + + SECTION("first iterable is empty") { + auto p = product(emp, n1, n2); + REQUIRE(std::begin(p) == std::end(p)); + } + + SECTION("middle iterable is empty") { + auto p = product(n1, emp, n2); + REQUIRE(std::begin(p) == std::end(p)); + } + + SECTION("last iterable is empty") { + auto p = product(n1, n2, emp); + REQUIRE(std::begin(p) == std::end(p)); + } } TEST_CASE("product: single iterable", "[product]") { - const std::string s{"ab"}; - using TP = std::tuple; - using ResType = const std::vector; + const std::string s{"ab"}; + using TP = std::tuple; + using ResType = const std::vector; - auto p = product(s); - ResType v(std::begin(p), std::end(p)); - ResType vc = {TP{'a'}, TP{'b'}}; + auto p = product(s); + ResType v(std::begin(p), std::end(p)); + ResType vc = {TP{'a'}, TP{'b'}}; - REQUIRE( v == vc ); + REQUIRE(v == vc); } TEST_CASE("product: no arguments gives one empty tuple", "[product") { - auto p = product(); - auto it = std::begin(p); - REQUIRE( it != std::end(p) ); - REQUIRE( *it == std::make_tuple() ); - ++it; - REQUIRE( it == std::end(p) ); + auto p = product(); + auto it = std::begin(p); + REQUIRE(it != std::end(p)); + REQUIRE(*it == std::make_tuple()); + ++it; + REQUIRE(it == std::end(p)); } TEST_CASE("product: binds to lvalues and moves rvalues", "[product]") { - itertest::BasicIterable bi{'x', 'y'}; - itertest::BasicIterable bi2{0, 1}; - - SECTION("First ref'd, second moved") { - product(bi, std::move(bi2)); - REQUIRE_FALSE( bi.was_moved_from() ); - REQUIRE( bi2.was_moved_from() ); - } - - SECTION("First moved, second ref'd") { - product(std::move(bi), bi2); - REQUIRE( bi.was_moved_from() ); - REQUIRE_FALSE( bi2.was_moved_from() ); - } + itertest::BasicIterable bi{'x', 'y'}; + itertest::BasicIterable bi2{0, 1}; + + SECTION("First ref'd, second moved") { + product(bi, std::move(bi2)); + REQUIRE_FALSE(bi.was_moved_from()); + REQUIRE(bi2.was_moved_from()); + } + + SECTION("First moved, second ref'd") { + product(std::move(bi), bi2); + REQUIRE(bi.was_moved_from()); + REQUIRE_FALSE(bi2.was_moved_from()); + } } TEST_CASE("product: doesn't move or copy elements of iterable", "[product]") { - constexpr itertest::SolidInt arr[] = {{1}, {0}, {2}}; - for (auto&& t : product(arr)) { - (void)std::get<0>(t); - } + constexpr itertest::SolidInt arr[] = {{1}, {0}, {2}}; + for (auto&& t : product(arr)) { + (void)std::get<0>(t); + } } TEST_CASE("product: iterator meets requirements", "[product]") { - std::string s{"abc"}; - auto c = product(s, s); - REQUIRE( itertest::IsIterator::value ); + std::string s{"abc"}; + auto c = product(s, s); + REQUIRE(itertest::IsIterator::value); +} + +template +using ImpT = decltype(product(std::declval()...)); +TEST_CASE("product: has correct ctor and assign ops", "[product]") { + using T = ImpT, std::vector>; + REQUIRE(itertest::IsMoveConstructibleOnly::value); } From ddb330607d86b8cab1a206b3019378876594fdee Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:24:40 -0700 Subject: [PATCH 1332/1866] tests repeat impl has move ctor only --- test/test_repeat.cpp | 110 ++++++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 48 deletions(-) diff --git a/test/test_repeat.cpp b/test/test_repeat.cpp index ee7c03e4..3cd928df 100644 --- a/test/test_repeat.cpp +++ b/test/test_repeat.cpp @@ -11,70 +11,84 @@ using iter::repeat; TEST_CASE("repeat: one argument keeps giving value back", "[repeat]") { - auto r = repeat('a'); - auto it = std::begin(r); - REQUIRE( *it == 'a' ); - ++it; - REQUIRE( *it == 'a' ); - ++it; - REQUIRE( *it == 'a' ); - ++it; - REQUIRE( *it == 'a' ); - ++it; - REQUIRE( *it == 'a' ); + auto r = repeat('a'); + auto it = std::begin(r); + REQUIRE(*it == 'a'); + ++it; + REQUIRE(*it == 'a'); + ++it; + REQUIRE(*it == 'a'); + ++it; + REQUIRE(*it == 'a'); + ++it; + REQUIRE(*it == 'a'); } TEST_CASE("repeat: can be used as constexpr", "[repeat]") { - static constexpr char c = 'a'; - { - constexpr auto r = repeat(c); - constexpr auto i = r.begin(); - constexpr char c2 = *i; - static_assert(c == c2, "repeat value not as expected"); - constexpr auto i2 = ++i; (void)i2; - } - - { - constexpr static auto r = repeat('a'); - constexpr auto i = r.begin(); - constexpr char c2 = *i; - static_assert(c2 == 'a', "repeat value not as expected"); - } - - { - constexpr auto r = repeat(c, 2); - constexpr auto i = r.begin(); - constexpr char c2 = *i; - static_assert( c2 == c, "repeat value not as expected"); - } + static constexpr char c = 'a'; + { + constexpr auto r = repeat(c); + constexpr auto i = r.begin(); + constexpr char c2 = *i; + static_assert(c == c2, "repeat value not as expected"); + constexpr auto i2 = ++i; + (void)i2; + } + + { + constexpr static auto r = repeat('a'); + constexpr auto i = r.begin(); + constexpr char c2 = *i; + static_assert(c2 == 'a', "repeat value not as expected"); + } + + { + constexpr auto r = repeat(c, 2); + constexpr auto i = r.begin(); + constexpr char c2 = *i; + static_assert(c2 == c, "repeat value not as expected"); + } } TEST_CASE("repeat: two argument repeats a number of times", "[repeat]") { - auto r = repeat('a', 3); - std::string s(std::begin(r), std::end(r)); - REQUIRE( s == "aaa" ); + auto r = repeat('a', 3); + std::string s(std::begin(r), std::end(r)); + REQUIRE(s == "aaa"); } TEST_CASE("repeat: 0 count gives empty sequence", "[repeat]") { - auto r = repeat('a', 0); - REQUIRE( std::begin(r) == std::end(r) ); + auto r = repeat('a', 0); + REQUIRE(std::begin(r) == std::end(r)); } TEST_CASE("repeat: negative count gives empty sequence", "[repeat]") { - auto r = repeat('a', -2); - REQUIRE( std::begin(r) == std::end(r) ); - auto r2 = repeat('a', -1); - REQUIRE( std::begin(r2) == std::end(r2) ); + auto r = repeat('a', -2); + REQUIRE(std::begin(r) == std::end(r)); + auto r2 = repeat('a', -1); + REQUIRE(std::begin(r2) == std::end(r2)); } TEST_CASE("repeat: doesn't duplicate item", "[repeat]") { - itertest::SolidInt si{2}; - auto r = repeat(si); - auto it = std::begin(r); - (void)*it; + itertest::SolidInt si{2}; + auto r = repeat(si); + auto it = std::begin(r); + (void)*it; } TEST_CASE("repeat: iterator meets requirements", "[repeat]") { - auto r = repeat(1); - REQUIRE( itertest::IsIterator::value ); + auto r = repeat(1); + REQUIRE(itertest::IsIterator::value); +} + +template +using ImpT = decltype(repeat(std::declval())); + +template +using ImpT2 = decltype(repeat(std::declval(), 1)); + +TEST_CASE("repeat: has correct ctor and assign ops", "[repeat]") { + REQUIRE(itertest::IsMoveConstructibleOnly>::value); + REQUIRE(itertest::IsMoveConstructibleOnly>::value); + REQUIRE(itertest::IsMoveConstructibleOnly>::value); + REQUIRE(itertest::IsMoveConstructibleOnly>::value); } From 1be704d461c86b124da6ef1965eb09bd34a9eb4a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:24:50 -0700 Subject: [PATCH 1333/1866] tests reversed impl has move ctor only --- test/test_reversed.cpp | 73 +++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/test/test_reversed.cpp b/test/test_reversed.cpp index cade9326..c245e82a 100644 --- a/test/test_reversed.cpp +++ b/test/test_reversed.cpp @@ -12,61 +12,68 @@ using iter::reversed; using Vec = const std::vector; TEST_CASE("reversed: can reverse a vector", "[reversed]") { - Vec ns = {10, 20, 30, 40}; - auto r = reversed(ns); + Vec ns = {10, 20, 30, 40}; + auto r = reversed(ns); - Vec v(std::begin(r), std::end(r)); - Vec vc = {40, 30, 20, 10}; + Vec v(std::begin(r), std::end(r)); + Vec vc = {40, 30, 20, 10}; - REQUIRE( v == vc ); + REQUIRE(v == vc); } TEST_CASE("reversed: can reverse an array", "[reversed]") { - int ns[] = {10, 20, 30, 40}; - auto r = reversed(ns); + int ns[] = {10, 20, 30, 40}; + auto r = reversed(ns); - Vec v(std::begin(r), std::end(r)); - Vec vc = {40, 30, 20, 10}; + Vec v(std::begin(r), std::end(r)); + Vec vc = {40, 30, 20, 10}; - REQUIRE( v == vc ); + REQUIRE(v == vc); } TEST_CASE("reversed: empty when iterable is empty", "[reversed]") { - Vec emp{}; - auto r = reversed(emp); - REQUIRE( std::begin(r) == std::end(r) ); + Vec emp{}; + auto r = reversed(emp); + REQUIRE(std::begin(r) == std::end(r)); } TEST_CASE("reversed: moves rvalues and binds to lvalues", "[reversed]") { - itertest::BasicIterable bi{1, 2}; - itertest::BasicIterable bi2{1, 2}; - reversed(bi); - REQUIRE_FALSE( bi.was_moved_from() ); + itertest::BasicIterable bi{1, 2}; + itertest::BasicIterable bi2{1, 2}; + reversed(bi); + REQUIRE_FALSE(bi.was_moved_from()); - reversed(std::move(bi2)); - REQUIRE( bi2.was_moved_from() ); + reversed(std::move(bi2)); + REQUIRE(bi2.was_moved_from()); } TEST_CASE("reversed: doesn't move or copy elements of array", "[reversed]") { - constexpr itertest::SolidInt arr[] = {{6}, {7}, {8}}; - for (auto&& i : reversed(arr)) { - (void)i; - } + constexpr itertest::SolidInt arr[] = {{6}, {7}, {8}}; + for (auto&& i : reversed(arr)) { + (void)i; + } } TEST_CASE("reversed: with iterable doesn't move or copy elems", "[reversed]") { - constexpr std::array arr{{{6}, {7}, {8}}}; - for (auto&& i : reversed(arr)) { - (void)i; - } + constexpr std::array arr{{{6}, {7}, {8}}}; + for (auto&& i : reversed(arr)) { + (void)i; + } } TEST_CASE("reversed: iterator meets requirements", "[reversed]") { - Vec v; - auto r = reversed(v); - REQUIRE( itertest::IsIterator::value ); + Vec v; + auto r = reversed(v); + REQUIRE(itertest::IsIterator::value); - int a[1]; - auto ra = reversed(a); - REQUIRE( itertest::IsIterator::value ); + int a[1]; + auto ra = reversed(a); + REQUIRE(itertest::IsIterator::value); +} + +template +using ImpT = decltype(reversed(std::declval())); +TEST_CASE("reversed: has correct ctor and assign ops", "[reversed]") { + REQUIRE(itertest::IsMoveConstructibleOnly>::value); + REQUIRE(itertest::IsMoveConstructibleOnly>::value); } From c3321696bbba1f318d7079997a4092d6c4d4fc61 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:25:00 -0700 Subject: [PATCH 1334/1866] tests slice impl has move ctor only --- test/test_slice.cpp | 116 +++++++++++++++++++++++--------------------- 1 file changed, 61 insertions(+), 55 deletions(-) diff --git a/test/test_slice.cpp b/test/test_slice.cpp index 921fab44..a94e8a14 100644 --- a/test/test_slice.cpp +++ b/test/test_slice.cpp @@ -11,99 +11,105 @@ using iter::slice; using Vec = const std::vector; TEST_CASE("slice: take from beginning", "[slice]") { - Vec ns = {10,11,12,13,14,15,16,17,18,19}; - auto sl = slice(ns, 5); + Vec ns = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; + auto sl = slice(ns, 5); - Vec v(std::begin(sl), std::end(sl)); - Vec vc = {10,11,12,13,14}; + Vec v(std::begin(sl), std::end(sl)); + Vec vc = {10, 11, 12, 13, 14}; - REQUIRE( v == vc ); + REQUIRE(v == vc); } TEST_CASE("slice: start and stop", "[slice]") { - Vec ns = {10,11,12,13,14,15,16,17,18,19}; - auto sl = slice(ns, 2, 6); + Vec ns = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; + auto sl = slice(ns, 2, 6); - Vec v(std::begin(sl), std::end(sl)); - Vec vc = {12, 13, 14, 15}; + Vec v(std::begin(sl), std::end(sl)); + Vec vc = {12, 13, 14, 15}; - REQUIRE( v == vc ); + REQUIRE(v == vc); } TEST_CASE("slice: start, stop, step", "[slice]") { - Vec ns = {10,11,12,13,14,15,16,17,18,19}; - auto sl = slice(ns, 2, 8, 2); + Vec ns = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; + auto sl = slice(ns, 2, 8, 2); - Vec v(std::begin(sl), std::end(sl)); - Vec vc = {12,14,16}; + Vec v(std::begin(sl), std::end(sl)); + Vec vc = {12, 14, 16}; - REQUIRE( v == vc ); + REQUIRE(v == vc); } TEST_CASE("slice: empty iterable", "[slice]") { - Vec ns{}; - auto sl = slice(ns, 3); - REQUIRE( std::begin(sl) == std::end(sl) ); + Vec ns{}; + auto sl = slice(ns, 3); + REQUIRE(std::begin(sl) == std::end(sl)); } TEST_CASE("slice: stop is beyond end of iterable", "[slice]") { - Vec ns = {1, 2, 3}; - auto sl = slice(ns, 10); + Vec ns = {1, 2, 3}; + auto sl = slice(ns, 10); - Vec v(std::begin(sl), std::end(sl)); - REQUIRE( v == ns ); + Vec v(std::begin(sl), std::end(sl)); + REQUIRE(v == ns); } TEST_CASE("slice: start is beyond end of iterable", "[slice]") { - Vec ns = {1, 2, 3}; - auto sl = slice(ns, 5, 10); - REQUIRE( std::begin(sl) == std::end(sl) ); + Vec ns = {1, 2, 3}; + auto sl = slice(ns, 5, 10); + REQUIRE(std::begin(sl) == std::end(sl)); } TEST_CASE("slice: (stop - start) % step != 0", "[slice]") { - Vec ns = {1, 2, 3, 4}; - auto sl = slice(ns, 0, 2, 3); - Vec v(std::begin(sl), std::end(sl)); - Vec vc = {1}; + Vec ns = {1, 2, 3, 4}; + auto sl = slice(ns, 0, 2, 3); + Vec v(std::begin(sl), std::end(sl)); + Vec vc = {1}; - REQUIRE( v == vc ); + REQUIRE(v == vc); } TEST_CASE("slice: invalid ranges give 0 size slices", "[slice]") { - Vec ns = {1, 2, 3}; - SECTION("negative step") { - auto sl = slice(ns, 1, 10, -1); - REQUIRE( std::begin(sl) == std::end(sl) ); - } - SECTION("stop < start") { - auto sl = slice(ns, 2, 0, 3); - REQUIRE( std::begin(sl) == std::end(sl) ); - } + Vec ns = {1, 2, 3}; + SECTION("negative step") { + auto sl = slice(ns, 1, 10, -1); + REQUIRE(std::begin(sl) == std::end(sl)); + } + SECTION("stop < start") { + auto sl = slice(ns, 2, 0, 3); + REQUIRE(std::begin(sl) == std::end(sl)); + } } TEST_CASE("slice: moves rvalues and binds to lvalues", "[slice]") { - itertest::BasicIterable bi{1, 2, 3, 4}; - slice(bi, 1, 3); - REQUIRE_FALSE( bi.was_moved_from() ); - auto sl = slice(std::move(bi), 1, 3); - REQUIRE( bi.was_moved_from() ); + itertest::BasicIterable bi{1, 2, 3, 4}; + slice(bi, 1, 3); + REQUIRE_FALSE(bi.was_moved_from()); + auto sl = slice(std::move(bi), 1, 3); + REQUIRE(bi.was_moved_from()); - Vec v(std::begin(sl), std::end(sl)); - Vec vc = {2, 3}; + Vec v(std::begin(sl), std::end(sl)); + Vec vc = {2, 3}; - REQUIRE( v == vc ); + REQUIRE(v == vc); } - TEST_CASE("slice: with iterable doesn't move or copy elems", "[slice]") { - constexpr itertest::SolidInt arr[] = {{6}, {7}, {8}}; - for (auto&& i : slice(arr, 2)) { - (void)i; - } + constexpr itertest::SolidInt arr[] = {{6}, {7}, {8}}; + for (auto&& i : slice(arr, 2)) { + (void)i; + } } TEST_CASE("slice: iterator meets requirements", "[slice]") { - std::string s{"abcdef"}; - auto c = slice(s, 1, 3); - REQUIRE( itertest::IsIterator::value ); + std::string s{"abcdef"}; + auto c = slice(s, 1, 3); + REQUIRE(itertest::IsIterator::value); +} + +template +using ImpT = decltype(slice(std::declval(), 1)); +TEST_CASE("slice: has correct ctor and assign ops", "[slice]") { + REQUIRE(itertest::IsMoveConstructibleOnly>::value); + REQUIRE(itertest::IsMoveConstructibleOnly>::value); } From 1486f6f057ff9b15cf9777e9588a3ac7cb52901d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:25:13 -0700 Subject: [PATCH 1335/1866] tests sliding_window impl has move ctor only --- test/test_sliding_window.cpp | 141 ++++++++++++++++++----------------- 1 file changed, 74 insertions(+), 67 deletions(-) diff --git a/test/test_sliding_window.cpp b/test/test_sliding_window.cpp index d413b431..d1c8cb18 100644 --- a/test/test_sliding_window.cpp +++ b/test/test_sliding_window.cpp @@ -12,96 +12,103 @@ using iter::sliding_window; using Vec = const std::vector; TEST_CASE("sliding_window: window of size 3", "[sliding_window]") { - Vec ns = { 10, 20, 30, 40, 50}; - auto sw = sliding_window(ns, 3); - auto it = std::begin(sw); - REQUIRE( it != std::end(sw) ); - { - Vec v(std::begin(*it), std::end(*it)); - Vec vc = {10, 20, 30}; - REQUIRE( v == vc ); - - } - ++it; - REQUIRE( it != std::end(sw) ); - { - Vec v(std::begin(*it), std::end(*it)); - Vec vc = {20, 30, 40}; - REQUIRE( v == vc ); - } - ++it; - REQUIRE( it != std::end(sw) ); - { - Vec v(std::begin(*it), std::end(*it)); - Vec vc = {30, 40, 50}; - REQUIRE( v == vc ); - } - ++it; - REQUIRE( it == std::end(sw) ); + Vec ns = {10, 20, 30, 40, 50}; + auto sw = sliding_window(ns, 3); + auto it = std::begin(sw); + REQUIRE(it != std::end(sw)); + { + Vec v(std::begin(*it), std::end(*it)); + Vec vc = {10, 20, 30}; + REQUIRE(v == vc); + } + ++it; + REQUIRE(it != std::end(sw)); + { + Vec v(std::begin(*it), std::end(*it)); + Vec vc = {20, 30, 40}; + REQUIRE(v == vc); + } + ++it; + REQUIRE(it != std::end(sw)); + { + Vec v(std::begin(*it), std::end(*it)); + Vec vc = {30, 40, 50}; + REQUIRE(v == vc); + } + ++it; + REQUIRE(it == std::end(sw)); } TEST_CASE("sliding window: oversized window is empty", "[sliding_window]") { - Vec ns = {10, 20, 30}; - auto sw = sliding_window(ns, 5); - REQUIRE( std::begin(sw) == std::end(sw) ); + Vec ns = {10, 20, 30}; + auto sw = sliding_window(ns, 5); + REQUIRE(std::begin(sw) == std::end(sw)); } TEST_CASE("sliding window: window size == len(iterable)", "[sliding_window]") { - Vec ns = {10, 20, 30}; - auto sw = sliding_window(ns, 3); - auto it = std::begin(sw); - REQUIRE( it != std::end(sw) ); + Vec ns = {10, 20, 30}; + auto sw = sliding_window(ns, 3); + auto it = std::begin(sw); + REQUIRE(it != std::end(sw)); - Vec v(std::begin(*it), std::end(*it)); + Vec v(std::begin(*it), std::end(*it)); - REQUIRE( ns == v ); - ++it; - REQUIRE( it == std::end(sw) ); + REQUIRE(ns == v); + ++it; + REQUIRE(it == std::end(sw)); } TEST_CASE("sliding window: empty iterable is empty", "[sliding_window]") { - Vec ns{}; - auto sw = sliding_window(ns, 1); - REQUIRE( std::begin(sw) == std::end(sw) ); + Vec ns{}; + auto sw = sliding_window(ns, 1); + REQUIRE(std::begin(sw) == std::end(sw)); } TEST_CASE("sliding window: window size of 1", "[sliding_window]") { - Vec ns = {10, 20, 30}; - auto sw = sliding_window(ns, 1); - auto it = std::begin(sw); - REQUIRE( *std::begin(*it) == 10 ); - ++it; - REQUIRE( *std::begin(*it) == 20 ); - ++it; - REQUIRE( *std::begin(*it) == 30 ); - ++it; - REQUIRE( it == std::end(sw) ); + Vec ns = {10, 20, 30}; + auto sw = sliding_window(ns, 1); + auto it = std::begin(sw); + REQUIRE(*std::begin(*it) == 10); + ++it; + REQUIRE(*std::begin(*it) == 20); + ++it; + REQUIRE(*std::begin(*it) == 30); + ++it; + REQUIRE(it == std::end(sw)); } TEST_CASE("sliding window: window size of 0", "[sliding_window]") { - Vec ns = {10, 20, 30}; - auto sw = sliding_window(ns, 0); - REQUIRE( std::begin(sw) == std::end(sw) ); + Vec ns = {10, 20, 30}; + auto sw = sliding_window(ns, 0); + REQUIRE(std::begin(sw) == std::end(sw)); } -TEST_CASE("sliding window: moves rvalues and binds to lvalues", - "[sliding_window]") { - itertest::BasicIterable bi{1, 2}; - sliding_window(bi, 1); - REQUIRE_FALSE( bi.was_moved_from() ); - sliding_window(std::move(bi), 1); - REQUIRE( bi.was_moved_from() ); +TEST_CASE( + "sliding window: moves rvalues and binds to lvalues", "[sliding_window]") { + itertest::BasicIterable bi{1, 2}; + sliding_window(bi, 1); + REQUIRE_FALSE(bi.was_moved_from()); + sliding_window(std::move(bi), 1); + REQUIRE(bi.was_moved_from()); } TEST_CASE("sliding window: doesn't copy elements", "[sliding_window]") { - constexpr std::array arr{{{6}, {7}, {8}}}; - for (auto&& i : sliding_window(arr, 1)) { - (void)*std::begin(i); - } + constexpr std::array arr{{{6}, {7}, {8}}}; + for (auto&& i : sliding_window(arr, 1)) { + (void)*std::begin(i); + } } TEST_CASE("sliding_window: iterator meets requirements", "[sliding_window]") { - std::string s{"abcdef"}; - auto c = sliding_window(s, 2); - REQUIRE( itertest::IsIterator::value ); + std::string s{"abcdef"}; + auto c = sliding_window(s, 2); + REQUIRE(itertest::IsIterator::value); +} + +template +using ImpT = decltype(sliding_window(std::declval(), 1)); +TEST_CASE( + "sliding_window: has correct ctor and assign ops", "[sliding_window]") { + REQUIRE(itertest::IsMoveConstructibleOnly>::value); + REQUIRE(itertest::IsMoveConstructibleOnly>::value); } From 17c67334c57852698ba9d95b3f4576bf30575a7d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:25:23 -0700 Subject: [PATCH 1336/1866] tests sorted impl has move ctor only --- test/test_sorted.cpp | 258 ++++++++++++++++++++++--------------------- 1 file changed, 133 insertions(+), 125 deletions(-) diff --git a/test/test_sorted.cpp b/test/test_sorted.cpp index 918dec7d..374bdcba 100644 --- a/test/test_sorted.cpp +++ b/test/test_sorted.cpp @@ -14,160 +14,168 @@ using iter::sorted; using Vec = const std::vector; -TEST_CASE("sorted: iterates through a vector in sorted order", "[sorted]" ){ - Vec ns = {4, 0, 5, 1, 6, 7, 9, 3, 2, 8}; - auto s = sorted(ns); - Vec v(std::begin(s), std::end(s)); - Vec vc = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - REQUIRE( v == vc ); +TEST_CASE("sorted: iterates through a vector in sorted order", "[sorted]") { + Vec ns = {4, 0, 5, 1, 6, 7, 9, 3, 2, 8}; + auto s = sorted(ns); + Vec v(std::begin(s), std::end(s)); + Vec vc = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + REQUIRE(v == vc); } TEST_CASE("sorted: can modify elements through sorted", "[sorted]") { - std::vector ns(3, 9); - for (auto&& n : sorted(ns)) { - n = -1; - } - Vec vc(3, -1); - REQUIRE( ns == vc ); + std::vector ns(3, 9); + for (auto&& n : sorted(ns)) { + n = -1; + } + Vec vc(3, -1); + REQUIRE(ns == vc); } TEST_CASE("sorted: can iterate over unordered container", "[sorted]") { - std::unordered_set ns = {1, 3, 2, 0, 4}; - auto s = sorted(ns); + std::unordered_set ns = {1, 3, 2, 0, 4}; + auto s = sorted(ns); - Vec v(std::begin(s), std::end(s)); - Vec vc = {0, 1, 2, 3, 4}; - REQUIRE( v == vc ); + Vec v(std::begin(s), std::end(s)); + Vec vc = {0, 1, 2, 3, 4}; + REQUIRE(v == vc); } TEST_CASE("sorted: empty when iterable is empty", "[sorted]") { - Vec ns{}; - auto s = sorted(ns); - REQUIRE( std::begin(s) == std::end(s) ); + Vec ns{}; + auto s = sorted(ns); + REQUIRE(std::begin(s) == std::end(s)); } namespace { - bool int_greater_than(int lhs, int rhs) { - return lhs > rhs; - } + bool int_greater_than(int lhs, int rhs) { + return lhs > rhs; + } - struct IntGreaterThan { - bool operator() (int lhs, int rhs) const { - return lhs > rhs; - } - }; + struct IntGreaterThan { + bool operator()(int lhs, int rhs) const { + return lhs > rhs; + } + }; } TEST_CASE("sorted: works with different functor types", "[sorted]") { - Vec ns = {4, 1, 3, 2, 0}; - std::vector v; - SECTION("with function pointer") { - auto s = sorted(ns, int_greater_than); - v.insert(v.begin(), std::begin(s), std::end(s)); + Vec ns = {4, 1, 3, 2, 0}; + std::vector v; + SECTION("with function pointer") { + auto s = sorted(ns, int_greater_than); + v.insert(v.begin(), std::begin(s), std::end(s)); + } + + SECTION("with callable object") { + auto s = sorted(ns, IntGreaterThan{}); + v.insert(v.begin(), std::begin(s), std::end(s)); + } + + SECTION("with lambda") { + auto s = sorted(ns, [](int lhs, int rhs) { return lhs > rhs; }); + v.insert(v.begin(), std::begin(s), std::end(s)); + } + + Vec vc = {4, 3, 2, 1, 0}; + REQUIRE(v == vc); +} + +namespace { + template + class BasicIterableWithConstDeref { + private: + T* data; + std::size_t size; + bool was_moved_from_ = false; + + public: + BasicIterableWithConstDeref(std::initializer_list il) + : data{new T[il.size()]}, size{il.size()} { + // would like to use enumerate, can't because it's for unit + // testing enumerate + std::size_t i = 0; + for (auto&& e : il) { + data[i] = e; + ++i; + } } - SECTION("with callable object") { - auto s = sorted(ns, IntGreaterThan{}); - v.insert(v.begin(), std::begin(s), std::end(s)); + BasicIterableWithConstDeref& operator=( + BasicIterableWithConstDeref&&) = delete; + BasicIterableWithConstDeref& operator=( + const BasicIterableWithConstDeref&) = delete; + BasicIterableWithConstDeref(const BasicIterableWithConstDeref&) = delete; + + BasicIterableWithConstDeref(BasicIterableWithConstDeref&& other) + : data{other.data}, size{other.size} { + other.data = nullptr; + other.was_moved_from_ = true; } - SECTION("with lambda") { - auto s = sorted(ns, [](int lhs, int rhs){return lhs > rhs;}); - v.insert(v.begin(), std::begin(s), std::end(s)); + bool was_moved_from() const { + return this->was_moved_from_; } - Vec vc = {4, 3, 2, 1, 0}; - REQUIRE( v == vc ); -} + ~BasicIterableWithConstDeref() { + delete[] this->data; + } -namespace { -template -class BasicIterableWithConstDeref { - private: - T *data; - std::size_t size; - bool was_moved_from_ = false; - public: - BasicIterableWithConstDeref(std::initializer_list il) - : data{new T[il.size()]}, - size{il.size()} - { - // would like to use enumerate, can't because it's for unit - // testing enumerate - std::size_t i = 0; - for (auto&& e : il) { - data[i] = e; - ++i; - } - } - - BasicIterableWithConstDeref& operator=(BasicIterableWithConstDeref&&) = delete; - BasicIterableWithConstDeref& operator=(const BasicIterableWithConstDeref&) = delete; - BasicIterableWithConstDeref(const BasicIterableWithConstDeref&) = delete; - - BasicIterableWithConstDeref(BasicIterableWithConstDeref&& other) - : data{other.data}, - size{other.size} - { - other.data = nullptr; - other.was_moved_from_ = true; - } - - bool was_moved_from() const { - return this->was_moved_from_; - } - - ~BasicIterableWithConstDeref() { - delete [] this->data; - } - - class Iterator { - private: - T *p; - public: - Iterator(T *b) : p{b} { } - bool operator!=(const Iterator& other) const { - return this->p != other.p; - } - - Iterator& operator++() { - ++this->p; - return *this; - } - - T& operator*() { - return *this->p; - } - - const T& operator*() const { - return *this->p; - } - }; - - Iterator begin() { - return {this->data}; - } - - Iterator end() { - return {this->data + this->size}; - } -}; + class Iterator { + private: + T* p; + + public: + Iterator(T* b) : p{b} {} + bool operator!=(const Iterator& other) const { + return this->p != other.p; + } + + Iterator& operator++() { + ++this->p; + return *this; + } + + T& operator*() { + return *this->p; + } + + const T& operator*() const { + return *this->p; + } + }; + + Iterator begin() { + return {this->data}; + } + + Iterator end() { + return {this->data + this->size}; + } + }; } TEST_CASE("sorted: moves rvalues and binds to lvalues", "[sorted]") { - BasicIterableWithConstDeref bi{1, 2}; - sorted(bi); - REQUIRE_FALSE( bi.was_moved_from() ); + BasicIterableWithConstDeref bi{1, 2}; + sorted(bi); + REQUIRE_FALSE(bi.was_moved_from()); - sorted(std::move(bi)); - REQUIRE( bi.was_moved_from() ); + sorted(std::move(bi)); + REQUIRE(bi.was_moved_from()); } TEST_CASE("sorted: doesn't move or copy elements of iterable", "[sorted]") { - using itertest::SolidInt; - constexpr SolidInt arr[] = {{6}, {7}, {8}}; - for (auto&& i : sorted(arr, [](const SolidInt& lhs, const SolidInt& rhs){ - return lhs.getint() < rhs.getint();})) { - (void)i; - } + using itertest::SolidInt; + constexpr SolidInt arr[] = {{6}, {7}, {8}}; + for (auto &&i : sorted(arr, [](const SolidInt &lhs, const SolidInt &rhs) { + return lhs.getint() < rhs.getint(); + })) { + (void)i; + } +} + +template +using ImpT = decltype(sorted(std::declval())); +TEST_CASE("sorted: has correct ctor and assign ops", "[sorted]") { + REQUIRE(itertest::IsMoveConstructibleOnly>::value); + REQUIRE(itertest::IsMoveConstructibleOnly>::value); } From 1bff0b7470156523566fa654b2ceac7c2c9ebfbb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:25:43 -0700 Subject: [PATCH 1337/1866] tests takewhile impl has move ctor only --- test/test_takewhile.cpp | 137 +++++++++++++++++++++------------------- 1 file changed, 73 insertions(+), 64 deletions(-) diff --git a/test/test_takewhile.cpp b/test/test_takewhile.cpp index 1d28b4d2..de3ecb60 100644 --- a/test/test_takewhile.cpp +++ b/test/test_takewhile.cpp @@ -11,93 +11,102 @@ using iter::takewhile; using Vec = const std::vector; - namespace { - bool under_ten(int i) { - return i < 10; - } + bool under_ten(int i) { + return i < 10; + } - struct UnderTen { - bool operator()(int i) { - return i < 10; - } - }; + struct UnderTen { + bool operator()(int i) { + return i < 10; + } + }; } TEST_CASE("takewhile: works with lambda, callable, and function pointer", - "[takewhile]") { - Vec ns = {1, 3, 5, 20, 2, 4, 6, 8}; - SECTION("function pointer") { - auto tw = takewhile(under_ten, ns); - Vec v(std::begin(tw), std::end(tw)); - Vec vc = {1, 3, 5}; - REQUIRE( v == vc ); - } + "[takewhile]") { + Vec ns = {1, 3, 5, 20, 2, 4, 6, 8}; + SECTION("function pointer") { + auto tw = takewhile(under_ten, ns); + Vec v(std::begin(tw), std::end(tw)); + Vec vc = {1, 3, 5}; + REQUIRE(v == vc); + } - SECTION("callable object") { - auto tw = takewhile(UnderTen{}, ns); - Vec v(std::begin(tw), std::end(tw)); - Vec vc = {1, 3, 5}; - REQUIRE( v == vc ); - } + SECTION("callable object") { + auto tw = takewhile(UnderTen{}, ns); + Vec v(std::begin(tw), std::end(tw)); + Vec vc = {1, 3, 5}; + REQUIRE(v == vc); + } - SECTION("lambda") { - auto tw = takewhile([](int i){ return i < 10; }, ns); - Vec v(std::begin(tw), std::end(tw)); - Vec vc = {1, 3, 5}; - REQUIRE( v == vc ); - } + SECTION("lambda") { + auto tw = takewhile([](int i) { return i < 10; }, ns); + Vec v(std::begin(tw), std::end(tw)); + Vec vc = {1, 3, 5}; + REQUIRE(v == vc); + } } TEST_CASE("takewhile: everything passes predicate", "[takewhile]") { - Vec ns{1, 2, 3}; - auto tw = takewhile(under_ten, ns); - Vec v(std::begin(tw), std::end(tw)); - Vec vc = {1, 2, 3}; + Vec ns{1, 2, 3}; + auto tw = takewhile(under_ten, ns); + Vec v(std::begin(tw), std::end(tw)); + Vec vc = {1, 2, 3}; } TEST_CASE("takewhile: empty iterable is empty", "[takewhile]") { - Vec ns{}; - auto tw = takewhile(under_ten, ns); - REQUIRE( std::begin(tw) == std::end(tw) ); + Vec ns{}; + auto tw = takewhile(under_ten, ns); + REQUIRE(std::begin(tw) == std::end(tw)); } -TEST_CASE("takewhile: when first element fails predicate, it's empty" - "[takewhile]") { - SECTION("First element is only element") { - Vec ns = {20}; - auto tw = takewhile(under_ten, ns); - REQUIRE( std::begin(tw) == std::end(tw) ); - } +TEST_CASE( + "takewhile: when first element fails predicate, it's empty" + "[takewhile]") { + SECTION("First element is only element") { + Vec ns = {20}; + auto tw = takewhile(under_ten, ns); + REQUIRE(std::begin(tw) == std::end(tw)); + } - SECTION("First element followed by elements that pass") { - Vec ns = {20, 1, 1}; - auto tw = takewhile(under_ten, ns); - REQUIRE( std::begin(tw) == std::end(tw) ); - } + SECTION("First element followed by elements that pass") { + Vec ns = {20, 1, 1}; + auto tw = takewhile(under_ten, ns); + REQUIRE(std::begin(tw) == std::end(tw)); + } } TEST_CASE("takewhile: moves rvalues, binds to lvalues", "[takewhile]") { - itertest::BasicIterable bi{1, 2}; - takewhile(under_ten, bi); - REQUIRE_FALSE( bi.was_moved_from() ); + itertest::BasicIterable bi{1, 2}; + takewhile(under_ten, bi); + REQUIRE_FALSE(bi.was_moved_from()); - takewhile(under_ten, std::move(bi)); - REQUIRE( bi.was_moved_from() ); + takewhile(under_ten, std::move(bi)); + REQUIRE(bi.was_moved_from()); } -TEST_CASE("takewhile: with iterable doesn't move or copy elements", - "[takewhile]") { - constexpr std::array arr{{{8}, {9}, {10}}}; - auto func = - [](const itertest::SolidInt& si){return si.getint() < 10;}; - for (auto&& i : takewhile(func, arr)) { - (void)i; - } +TEST_CASE( + "takewhile: with iterable doesn't move or copy elements", "[takewhile]") { + constexpr std::array arr{{{8}, {9}, {10}}}; + auto func = [](const itertest::SolidInt& si) { return si.getint() < 10; }; + for (auto&& i : takewhile(func, arr)) { + (void)i; + } } TEST_CASE("takewhile: iterator meets requirements", "[takewhile]") { - std::string s{}; - auto c = takewhile([]{return true;}, s); - REQUIRE( itertest::IsIterator::value ); + std::string s{}; + auto c = takewhile([] { return true; }, s); + REQUIRE(itertest::IsIterator::value); +} + +template +using ImpT = decltype(takewhile(std::declval(), std::declval())); +TEST_CASE("takewhile: has correct ctor and assign ops", "[takewhile]") { + using T1 = ImpT; + auto lam = [](char) { return false; }; + using T2 = ImpT; + REQUIRE(itertest::IsMoveConstructibleOnly::value); + REQUIRE(itertest::IsMoveConstructibleOnly::value); } From cc3bcd3d0f0e53a877e3c176e52c357f172480e5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:25:52 -0700 Subject: [PATCH 1338/1866] tests justseen impl has move ctor only --- test/test_unique_justseen.cpp | 54 ++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/test/test_unique_justseen.cpp b/test/test_unique_justseen.cpp index 4285f364..1167594f 100644 --- a/test/test_unique_justseen.cpp +++ b/test/test_unique_justseen.cpp @@ -13,40 +13,48 @@ using iter::unique_justseen; using Vec = const std::vector; TEST_CASE("unique justseen: adjacent repeating values", "[unique_justseen]") { - Vec ns = {1,1,1,2,2,3,4,4,5,6,7,8,8,8,8,9,9}; - auto ue = unique_justseen(ns); - Vec v(std::begin(ue), std::end(ue)); - Vec vc = {1,2,3,4,5,6,7,8,9}; - REQUIRE( v == vc ); + Vec ns = {1, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7, 8, 8, 8, 8, 9, 9}; + auto ue = unique_justseen(ns); + Vec v(std::begin(ue), std::end(ue)); + Vec vc = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + REQUIRE(v == vc); } TEST_CASE("unique justseen: some repeating values", "[unique_justseen]") { - Vec ns = {1,2,2,3,4,4,5,6,6}; - auto ue = unique_justseen(ns); - Vec v(std::begin(ue), std::end(ue)); - Vec vc = {1,2,3,4,5,6}; - REQUIRE( v == vc ); + Vec ns = {1, 2, 2, 3, 4, 4, 5, 6, 6}; + auto ue = unique_justseen(ns); + Vec v(std::begin(ue), std::end(ue)); + Vec vc = {1, 2, 3, 4, 5, 6}; + REQUIRE(v == vc); } TEST_CASE("unique justseen: doesn't omit non-adjacent duplicates", - "[unique_justseen]") { - Vec ns = {1,2,3,2,1,2,3,2,1}; - auto ue = unique_justseen(ns); - Vec v(std::begin(ue), std::end(ue)); - REQUIRE( v == ns ); + "[unique_justseen]") { + Vec ns = {1, 2, 3, 2, 1, 2, 3, 2, 1}; + auto ue = unique_justseen(ns); + Vec v(std::begin(ue), std::end(ue)); + REQUIRE(v == ns); } TEST_CASE("unique justseen: moves and binds correctly", "[unique_justseen]") { - itertest::BasicIterable bi{1, 2}; - unique_justseen(bi); - REQUIRE_FALSE( bi.was_moved_from() ); + itertest::BasicIterable bi{1, 2}; + unique_justseen(bi); + REQUIRE_FALSE(bi.was_moved_from()); - unique_justseen(std::move(bi)); - REQUIRE( bi.was_moved_from() ); + unique_justseen(std::move(bi)); + REQUIRE(bi.was_moved_from()); } TEST_CASE("unique_justseen: iterator meets requirements", "[unique_justseen]") { - std::string s{}; - auto c = unique_justseen(s); - REQUIRE( itertest::IsIterator::value ); + std::string s{}; + auto c = unique_justseen(s); + REQUIRE(itertest::IsIterator::value); +} + +template +using ImpT = decltype(unique_justseen(std::declval())); +TEST_CASE( + "unique_justseen: has correct ctor and assign ops", "[unique_justseen]") { + REQUIRE(itertest::IsMoveConstructibleOnly>::value); + REQUIRE(itertest::IsMoveConstructibleOnly>::value); } From a43682efeed5f4165a05387f630b571b7c268b7b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:26:17 -0700 Subject: [PATCH 1339/1866] tests everseen impl has move ctor only --- test/test_unique_everseen.cpp | 52 ++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/test/test_unique_everseen.cpp b/test/test_unique_everseen.cpp index 4cd94cd2..76151efe 100644 --- a/test/test_unique_everseen.cpp +++ b/test/test_unique_everseen.cpp @@ -13,34 +13,42 @@ using iter::unique_everseen; using Vec = const std::vector; TEST_CASE("unique everseen: adjacent repeating values", "[unique_everseen]") { - Vec ns = {1,1,1,2,2,3,4,4,5,6,7,8,8,8,8,9,9}; - auto ue = unique_everseen(ns); - Vec v(std::begin(ue), std::end(ue)); - Vec vc = {1,2,3,4,5,6,7,8,9}; - REQUIRE( v == vc ); + Vec ns = {1, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7, 8, 8, 8, 8, 9, 9}; + auto ue = unique_everseen(ns); + Vec v(std::begin(ue), std::end(ue)); + Vec vc = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + REQUIRE(v == vc); } -TEST_CASE("unique everseen: nonadjacent repeating values", - "[unique_everseen]") { - Vec ns = {1,2,3,4,3,2,1,5,6}; - auto ue = unique_everseen(ns); - Vec v(std::begin(ue), std::end(ue)); - Vec vc = {1,2,3,4,5,6}; - REQUIRE( v == vc ); +TEST_CASE( + "unique everseen: nonadjacent repeating values", "[unique_everseen]") { + Vec ns = {1, 2, 3, 4, 3, 2, 1, 5, 6}; + auto ue = unique_everseen(ns); + Vec v(std::begin(ue), std::end(ue)); + Vec vc = {1, 2, 3, 4, 5, 6}; + REQUIRE(v == vc); } -TEST_CASE("unique everseen: moves rvalues, binds to lvalues", - "[unique_everseen]") { - itertest::BasicIterable bi{1, 2}; - unique_everseen(bi); - REQUIRE_FALSE( bi.was_moved_from() ); +TEST_CASE( + "unique everseen: moves rvalues, binds to lvalues", "[unique_everseen]") { + itertest::BasicIterable bi{1, 2}; + unique_everseen(bi); + REQUIRE_FALSE(bi.was_moved_from()); - unique_everseen(std::move(bi)); - REQUIRE( bi.was_moved_from() ); + unique_everseen(std::move(bi)); + REQUIRE(bi.was_moved_from()); } TEST_CASE("unique_everseen: iterator meets requirements", "[unique_everseen]") { - std::string s{}; - auto c = unique_everseen(s); - REQUIRE( itertest::IsIterator::value ); + std::string s{}; + auto c = unique_everseen(s); + REQUIRE(itertest::IsIterator::value); +} + +template +using ImpT = decltype(unique_everseen(std::declval())); +TEST_CASE( + "unique_everseen: has correct ctor and assign ops", "[unique_everseen]") { + REQUIRE(itertest::IsMoveConstructibleOnly>::value); + REQUIRE(itertest::IsMoveConstructibleOnly>::value); } From cb0363a2bf72788a00a68ae596d5ae27a37cdc29 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:26:32 -0700 Subject: [PATCH 1340/1866] tests zip has move ctor only --- test/test_zip.cpp | 123 ++++++++++++++++++++++++---------------------- 1 file changed, 65 insertions(+), 58 deletions(-) diff --git a/test/test_zip.cpp b/test/test_zip.cpp index f099c8eb..d8cb80e5 100644 --- a/test/test_zip.cpp +++ b/test/test_zip.cpp @@ -17,93 +17,100 @@ using itertest::BasicIterable; using itertest::SolidInt; TEST_CASE("zip: Simple case, same length", "[zip]") { - using Tu = std::tuple; - using ResVec = const std::vector; - std::vector iv {10, 20, 30}; - std::string s{"hey"}; - double arr[] = {1.0, 2.0, 4.0}; - - auto z = zip(iv, s, arr); - ResVec v(std::begin(z), std::end(z)); - ResVec vc {Tu{10, 'h', 1.0}, Tu{20, 'e', 2.0}, Tu{30, 'y', 4.0}}; - REQUIRE( v == vc ); + using Tu = std::tuple; + using ResVec = const std::vector; + std::vector iv{10, 20, 30}; + std::string s{"hey"}; + double arr[] = {1.0, 2.0, 4.0}; + + auto z = zip(iv, s, arr); + ResVec v(std::begin(z), std::end(z)); + ResVec vc{Tu{10, 'h', 1.0}, Tu{20, 'e', 2.0}, Tu{30, 'y', 4.0}}; + REQUIRE(v == vc); } TEST_CASE("zip: One empty, all empty", "[zip]") { - std::vector iv = {1,2,3}; - std::string s{}; - auto z = zip(iv, s); - REQUIRE_FALSE( std::begin(z) != std::end(z) ); - auto z2 = zip(s, iv); - REQUIRE_FALSE( std::begin(z2) != std::end(z2) ); + std::vector iv = {1, 2, 3}; + std::string s{}; + auto z = zip(iv, s); + REQUIRE_FALSE(std::begin(z) != std::end(z)); + auto z2 = zip(s, iv); + REQUIRE_FALSE(std::begin(z2) != std::end(z2)); } TEST_CASE("zip: terminates on shortest sequence", "[zip]") { - std::vector iv{1,2,3,4,5}; - std::string s{"hi"}; - auto z = zip(iv, s); + std::vector iv{1, 2, 3, 4, 5}; + std::string s{"hi"}; + auto z = zip(iv, s); - REQUIRE( std::distance(std::begin(z), std::end(z)) == 2 ); + REQUIRE(std::distance(std::begin(z), std::end(z)) == 2); } TEST_CASE("zip: Empty", "[zip]") { - auto z = zip(); - REQUIRE_FALSE( std::begin(z) != std::end(z) ); + auto z = zip(); + REQUIRE_FALSE(std::begin(z) != std::end(z)); } TEST_CASE("zip: Modify sequence through zip", "[zip]") { - std::vector iv{1,2,3}; - std::vector iv2{1,2,3,4}; - for (auto&& t : zip(iv, iv2)) { - std::get<0>(t) = -1; - std::get<1>(t) = -1; - } - - const std::vector vc{-1, -1, -1}; - const std::vector vc2{-1, -1, -1, 4}; - REQUIRE( iv == vc); - REQUIRE( iv2 == vc2); + std::vector iv{1, 2, 3}; + std::vector iv2{1, 2, 3, 4}; + for (auto&& t : zip(iv, iv2)) { + std::get<0>(t) = -1; + std::get<1>(t) = -1; + } + + const std::vector vc{-1, -1, -1}; + const std::vector vc2{-1, -1, -1, 4}; + REQUIRE(iv == vc); + REQUIRE(iv2 == vc2); } TEST_CASE("zip: binds reference when it should", "[zip]") { - BasicIterable bi{'x', 'y', 'z'}; - zip(bi); - REQUIRE_FALSE( bi.was_moved_from() ); + BasicIterable bi{'x', 'y', 'z'}; + zip(bi); + REQUIRE_FALSE(bi.was_moved_from()); } TEST_CASE("zip: moves rvalues", "[zip]") { - BasicIterable bi{'x', 'y', 'z'}; - zip(std::move(bi)); - REQUIRE( bi.was_moved_from() ); + BasicIterable bi{'x', 'y', 'z'}; + zip(std::move(bi)); + REQUIRE(bi.was_moved_from()); } TEST_CASE("zip: Can bind ref and move in single zip", "[zip]") { - BasicIterable b1{'x', 'y', 'z'}; - BasicIterable b2{'a', 'b'}; - zip(b1, std::move(b2)); - REQUIRE_FALSE( b1.was_moved_from() ); - REQUIRE( b2.was_moved_from() ); + BasicIterable b1{'x', 'y', 'z'}; + BasicIterable b2{'a', 'b'}; + zip(b1, std::move(b2)); + REQUIRE_FALSE(b1.was_moved_from()); + REQUIRE(b2.was_moved_from()); } TEST_CASE("zip: doesn't move or copy elements of iterable", "[zip]") { - constexpr SolidInt arr[] = {{6}, {7}, {8}}; - for (auto&& t : zip(arr)) { - (void)std::get<0>(t); - } + constexpr SolidInt arr[] = {{6}, {7}, {8}}; + for (auto&& t : zip(arr)) { + (void)std::get<0>(t); + } } TEST_CASE("zip: postfix ++", "[zip]") { - const std::vector v = {1}; - auto z = zip(v); - auto it = std::begin(z); - it++; - REQUIRE( it == std::end(z) ); + const std::vector v = {1}; + auto z = zip(v); + auto it = std::begin(z); + it++; + REQUIRE(it == std::end(z)); } TEST_CASE("zip: iterator meets requirements", "[zip]") { - std::string s{}; - auto c = zip(s); - REQUIRE( itertest::IsIterator::value ); - auto c2 = zip(s, s); - REQUIRE( itertest::IsIterator::value ); + std::string s{}; + auto c = zip(s); + REQUIRE(itertest::IsIterator::value); + auto c2 = zip(s, s); + REQUIRE(itertest::IsIterator::value); +} + +template +using ImpT = decltype(zip(std::declval()...)); +TEST_CASE("zip: has correct ctor and assign ops", "[zip]") { + using T = ImpT, std::vector>; + REQUIRE(itertest::IsMoveConstructibleOnly::value); } From 7a7dc8b9ba0dbb0a43b34c08e5ae20ee372d507e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:26:40 -0700 Subject: [PATCH 1341/1866] tests zip_longest has move ctor only --- test/test_zip_longest.cpp | 198 ++++++++++++++++++-------------------- 1 file changed, 96 insertions(+), 102 deletions(-) diff --git a/test/test_zip_longest.cpp b/test/test_zip_longest.cpp index 6fe8cf5a..c8694e9e 100644 --- a/test/test_zip_longest.cpp +++ b/test/test_zip_longest.cpp @@ -17,135 +17,129 @@ using iter::zip_longest; // reopening boost is the only way I can find that gets this to print namespace boost { -template -std::ostream& operator<<(std::ostream& out, const optional& opt) { + template + std::ostream& operator<<(std::ostream& out, const optional& opt) { if (opt) { - out << "Just " << *opt; + out << "Just " << *opt; } else { - out << "Nothing"; + out << "Nothing"; } return out; -} + } } template using const_opt_tuple = std::tuple...>; -TEST_CASE("zip longest: correctly detects longest at any position", - "[zip_longest]") { - - const std::vector ivec{2, 4, 6, 8, 10, 12}; - const std::vector svec{"abc", "def", "xyz"}; - const std::string str{"hello"}; - - SECTION("longest first") { - using TP = const_opt_tuple; - using ResVec = std::vector; - - auto zl = zip_longest(ivec, svec, str); - ResVec results(std::begin(zl), std::end(zl)); - ResVec rc = { - TP{{ivec[0]}, {svec[0]}, {str[0]}}, - TP{{ivec[1]}, {svec[1]}, {str[1]}}, - TP{{ivec[2]}, {svec[2]}, {str[2]}}, - TP{{ivec[3]}, {}, {str[3]}}, - TP{{ivec[4]}, {}, {str[4]}}, - TP{{ivec[5]}, {}, {} } - }; - - REQUIRE( results == rc ); - } +TEST_CASE( + "zip longest: correctly detects longest at any position", "[zip_longest]") { + const std::vector ivec{2, 4, 6, 8, 10, 12}; + const std::vector svec{"abc", "def", "xyz"}; + const std::string str{"hello"}; - SECTION("longest in middle") { - using TP = const_opt_tuple; - using ResVec = std::vector; - - auto zl = zip_longest(svec, ivec, str); - ResVec results(std::begin(zl), std::end(zl)); - ResVec rc = { - TP{{svec[0]}, {ivec[0]}, {str[0]}}, - TP{{svec[1]}, {ivec[1]}, {str[1]}}, - TP{{svec[2]}, {ivec[2]}, {str[2]}}, - TP{{}, {ivec[3]}, {str[3]}}, - TP{{}, {ivec[4]}, {str[4]}}, - TP{{}, {ivec[5]}, {} } - }; - - REQUIRE( results == rc ); - } + SECTION("longest first") { + using TP = const_opt_tuple; + using ResVec = std::vector; - SECTION("longest at end") { - using TP = const_opt_tuple; - using ResVec = std::vector; - - auto zl = zip_longest(svec, str, ivec); - ResVec results(std::begin(zl), std::end(zl)); - ResVec rc = { - TP{{svec[0]}, {str[0]}, {ivec[0]}}, - TP{{svec[1]}, {str[1]}, {ivec[1]}}, - TP{{svec[2]}, {str[2]}, {ivec[2]}}, - TP{{}, {str[3]}, {ivec[3]}}, - TP{{}, {str[4]}, {ivec[4]}}, - TP{{}, {}, {ivec[5]}} - }; - - REQUIRE( results == rc ); - } + auto zl = zip_longest(ivec, svec, str); + ResVec results(std::begin(zl), std::end(zl)); + ResVec rc = {TP{{ivec[0]}, {svec[0]}, {str[0]}}, + TP{{ivec[1]}, {svec[1]}, {str[1]}}, TP{{ivec[2]}, {svec[2]}, {str[2]}}, + TP{{ivec[3]}, {}, {str[3]}}, TP{{ivec[4]}, {}, {str[4]}}, + TP{{ivec[5]}, {}, {}}}; + + REQUIRE(results == rc); + } + + SECTION("longest in middle") { + using TP = const_opt_tuple; + using ResVec = std::vector; + + auto zl = zip_longest(svec, ivec, str); + ResVec results(std::begin(zl), std::end(zl)); + ResVec rc = {TP{{svec[0]}, {ivec[0]}, {str[0]}}, + TP{{svec[1]}, {ivec[1]}, {str[1]}}, TP{{svec[2]}, {ivec[2]}, {str[2]}}, + TP{{}, {ivec[3]}, {str[3]}}, TP{{}, {ivec[4]}, {str[4]}}, + TP{{}, {ivec[5]}, {}}}; + + REQUIRE(results == rc); + } + + SECTION("longest at end") { + using TP = const_opt_tuple; + using ResVec = std::vector; + + auto zl = zip_longest(svec, str, ivec); + ResVec results(std::begin(zl), std::end(zl)); + ResVec rc = {TP{{svec[0]}, {str[0]}, {ivec[0]}}, + TP{{svec[1]}, {str[1]}, {ivec[1]}}, TP{{svec[2]}, {str[2]}, {ivec[2]}}, + TP{{}, {str[3]}, {ivec[3]}}, TP{{}, {str[4]}, {ivec[4]}}, + TP{{}, {}, {ivec[5]}}}; + + REQUIRE(results == rc); + } } -TEST_CASE("zip longest: when all are empty, terminates right away", - "[zip_longest]") { - const std::vector ivec{}; - const std::vector svec{}; - const std::string str{}; +TEST_CASE( + "zip longest: when all are empty, terminates right away", "[zip_longest]") { + const std::vector ivec{}; + const std::vector svec{}; + const std::string str{}; - auto zl = zip_longest(ivec, svec, str); - REQUIRE( std::begin(zl) == std::end(zl) ); + auto zl = zip_longest(ivec, svec, str); + REQUIRE(std::begin(zl) == std::end(zl)); } TEST_CASE("zip longest: can modify zipped sequences", "[zip_longest]") { - std::vector ns1 = {1, 2, 3}; - std::vector ns2 = {10, 11, 12}; - for (auto&& t : zip_longest(ns1, ns2)) { - *std::get<0>(t) = -1; - *std::get<1>(t) = -1; - } - - std::vector vc = {-1, -1, -1}; - REQUIRE( ns1 == vc ); - REQUIRE( ns2 == vc ); + std::vector ns1 = {1, 2, 3}; + std::vector ns2 = {10, 11, 12}; + for (auto&& t : zip_longest(ns1, ns2)) { + *std::get<0>(t) = -1; + *std::get<1>(t) = -1; + } + + std::vector vc = {-1, -1, -1}; + REQUIRE(ns1 == vc); + REQUIRE(ns2 == vc); } TEST_CASE("zip longest: empty zip_longest() is empty", "[zip_longest]") { - auto zl = zip_longest(); - REQUIRE( std::begin(zl) == std::end(zl) ); - REQUIRE_FALSE( std::begin(zl) != std::end(zl) ); + auto zl = zip_longest(); + REQUIRE(std::begin(zl) == std::end(zl)); + REQUIRE_FALSE(std::begin(zl) != std::end(zl)); } TEST_CASE("zip_longest: binds to lvalues, moves rvalues", "[zip_longest]") { - itertest::BasicIterable b1{'x', 'y', 'z'}; - itertest::BasicIterable b2{'a', 'b'}; - SECTION("bind to first, moves second") { - zip_longest(b1, std::move(b2)); - } - SECTION("move first, bind to second") { - zip_longest(std::move(b2), b1); - } - REQUIRE_FALSE( b1.was_moved_from() ); - REQUIRE( b2.was_moved_from() ); + itertest::BasicIterable b1{'x', 'y', 'z'}; + itertest::BasicIterable b2{'a', 'b'}; + SECTION("bind to first, moves second") { + zip_longest(b1, std::move(b2)); + } + SECTION("move first, bind to second") { + zip_longest(std::move(b2), b1); + } + REQUIRE_FALSE(b1.was_moved_from()); + REQUIRE(b2.was_moved_from()); } TEST_CASE("zip_longest: doesn't move or copy elements", "[zip_longest]") { - constexpr itertest::SolidInt arr[] = {{6}, {7}, {8}}; - for (auto&& t : zip_longest(arr, arr)) { - (void)std::get<0>(t); - } + constexpr itertest::SolidInt arr[] = {{6}, {7}, {8}}; + for (auto&& t : zip_longest(arr, arr)) { + (void)std::get<0>(t); + } } TEST_CASE("zip_longest: iterator meets requirements", "[zip_longest]") { - std::string s{}; - auto c = zip_longest(s); - REQUIRE( itertest::IsIterator::value ); - auto c2 = zip_longest(s, s); - REQUIRE( itertest::IsIterator::value ); + std::string s{}; + auto c = zip_longest(s); + REQUIRE(itertest::IsIterator::value); + auto c2 = zip_longest(s, s); + REQUIRE(itertest::IsIterator::value); +} + +template +using ImpT = decltype(zip_longest(std::declval()...)); +TEST_CASE("zip_longest: has correct ctor and assign ops", "[zip_longest]") { + using T = ImpT, std::vector>; + REQUIRE(itertest::IsMoveConstructibleOnly::value); } From b5d12cd2881724d11176857cfbfc348908981d91 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:27:07 -0700 Subject: [PATCH 1342/1866] formats tests --- test/test_count.cpp | 74 +++++---- test/test_helpers.cpp | 94 +++++------ test/test_iteratoriterator.cpp | 82 ++++----- test/test_mixed.cpp | 179 ++++++++++---------- test/test_range.cpp | 296 ++++++++++++++++----------------- 5 files changed, 360 insertions(+), 365 deletions(-) diff --git a/test/test_count.cpp b/test/test_count.cpp index 0b861bbf..643819ea 100644 --- a/test/test_count.cpp +++ b/test/test_count.cpp @@ -10,60 +10,62 @@ using iter::count; TEST_CASE("count: watch for 10 elements", "[count]") { - std::vector v{}; - for (auto i : count()) { - v.push_back(i); - if (i == 9) break; - } + std::vector v{}; + for (auto i : count()) { + v.push_back(i); + if (i == 9) break; + } - const std::vector vc{0,1,2,3,4,5,6,7,8,9}; - REQUIRE( v == vc ); + const std::vector vc{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + REQUIRE(v == vc); } TEST_CASE("count: start at 10", "[count]") { - std::vector v{}; - for (auto i : count(10)) { - v.push_back(i); - if (i == 14) break; - } + std::vector v{}; + for (auto i : count(10)) { + v.push_back(i); + if (i == 14) break; + } - const std::vector vc{10,11,12,13,14}; - REQUIRE( v == vc ); + const std::vector vc{10, 11, 12, 13, 14}; + REQUIRE(v == vc); } TEST_CASE("count: with step", "[count]") { - std::vector v{}; - for (auto i : count(2, -1)) { - v.push_back(i); - if (i == -3) break; - } + std::vector v{}; + for (auto i : count(2, -1)) { + v.push_back(i); + if (i == -3) break; + } - const std::vector vc{2,1,0,-1,-2,-3}; - REQUIRE( v == vc); + const std::vector vc{2, 1, 0, -1, -2, -3}; + REQUIRE(v == vc); } TEST_CASE("count: with step > 1", "[count]") { - std::vector v{}; - for (auto i : count(10, 2)) { - v.push_back(i); - if (i == 16) break; - } + std::vector v{}; + for (auto i : count(10, 2)) { + v.push_back(i); + if (i == 16) break; + } - const std::vector vc{10, 12, 14, 16}; - REQUIRE( v == vc ); + const std::vector vc{10, 12, 14, 16}; + REQUIRE(v == vc); } TEST_CASE("count: can bo constexpr", "[count]") { - constexpr auto c = count(); - constexpr auto c2 = count(5); (void)c2; - constexpr auto c3 = count(5, 2); (void)c3; + constexpr auto c = count(); + constexpr auto c2 = count(5); + (void)c2; + constexpr auto c3 = count(5, 2); + (void)c3; - constexpr auto it = c.begin(); - constexpr auto i = *it; - static_assert(i == 0, "count begin not correct value"); + constexpr auto it = c.begin(); + constexpr auto i = *it; + static_assert(i == 0, "count begin not correct value"); } TEST_CASE("count: iterator meets requirements", "[count]") { - auto c = count(); - REQUIRE( itertest::IsIterator::value ); + auto c = count(); + REQUIRE(itertest::IsIterator::value); } diff --git a/test/test_helpers.cpp b/test/test_helpers.cpp index ad456f6c..f0e36990 100644 --- a/test/test_helpers.cpp +++ b/test/test_helpers.cpp @@ -9,78 +9,78 @@ using itertest::IsMoveConstructibleOnly; namespace { -class ValidIter { - private: - int i; - public: - ValidIter& operator++(); // prefix - ValidIter operator++(int); // postfix - bool operator==(const ValidIter&) const; - bool operator!=(const ValidIter&) const; - int operator*(); - void* operator->(); -}; - + class ValidIter { + private: + int i; + + public: + ValidIter& operator++(); // prefix + ValidIter operator++(int); // postfix + bool operator==(const ValidIter&) const; + bool operator!=(const ValidIter&) const; + int operator*(); + void* operator->(); + }; } TEST_CASE("IsIterator fails when missing prefix ++", "[helpers]") { - struct InvalidIter : ValidIter { - InvalidIter& operator++() = delete; - }; + struct InvalidIter : ValidIter { + InvalidIter& operator++() = delete; + }; - REQUIRE( !IsIterator::value ); + REQUIRE(!IsIterator::value); } TEST_CASE("IsIterator fails when missing postfix ++", "[helpers]") { - struct InvalidIter : ValidIter { - InvalidIter operator++(int) = delete; - }; + struct InvalidIter : ValidIter { + InvalidIter operator++(int) = delete; + }; - REQUIRE( !IsIterator::value ); + REQUIRE(!IsIterator::value); } TEST_CASE("IsIterator fails when missing ==", "[helpers]") { - struct InvalidIter : ValidIter { - bool operator==(const InvalidIter&) const = delete; - }; + struct InvalidIter : ValidIter { + bool operator==(const InvalidIter&) const = delete; + }; - REQUIRE( !IsIterator::value ); + REQUIRE(!IsIterator::value); } TEST_CASE("IsIterator fails when missing !=", "[helpers]") { - struct InvalidIter : ValidIter { - bool operator!=(const InvalidIter&) const = delete; - }; + struct InvalidIter : ValidIter { + bool operator!=(const InvalidIter&) const = delete; + }; - REQUIRE( !IsIterator::value ); + REQUIRE(!IsIterator::value); } TEST_CASE("IsIterator fails when missing *", "[helpers]") { - struct InvalidIter : ValidIter { - int operator*() = delete; - }; + struct InvalidIter : ValidIter { + int operator*() = delete; + }; - REQUIRE( !IsIterator::value ); + REQUIRE(!IsIterator::value); } TEST_CASE("IsIterator fails when missing copy-ctor", "[helpers]") { - struct InvalidIter : ValidIter { - InvalidIter(const InvalidIter&) = delete; - }; + struct InvalidIter : ValidIter { + InvalidIter(const InvalidIter&) = delete; + }; - REQUIRE( !IsIterator::value ); + REQUIRE(!IsIterator::value); } TEST_CASE("IsIterator fails when missing copy assignment", "[helpers]") { - struct InvalidIter : ValidIter { - InvalidIter& operator=(const InvalidIter&) = delete; - }; + struct InvalidIter : ValidIter { + InvalidIter& operator=(const InvalidIter&) = delete; + }; - REQUIRE( !IsIterator::value ); + REQUIRE(!IsIterator::value); } TEST_CASE("IsIterator passes a valid iterator", "[helpers]") { - REQUIRE( IsIterator::value ); + REQUIRE(IsIterator::value); } struct HasNothing { @@ -100,7 +100,7 @@ struct HasMoveCtorAndAssign { struct HasMoveCtorAndCopyAssign { HasMoveCtorAndCopyAssign(HasMoveCtorAndCopyAssign&&); - HasMoveCtorAndCopyAssign& operator=(const HasMoveCtorAndCopyAssign&); + HasMoveCtorAndCopyAssign& operator=(const HasMoveCtorAndCopyAssign&); }; struct HasMoveCtorOnly { @@ -108,20 +108,20 @@ struct HasMoveCtorOnly { }; TEST_CASE("IsMoveConstructibleOnly false without move ctor", "[helpers]") { - REQUIRE_FALSE( IsMoveConstructibleOnly::value ); + REQUIRE_FALSE(IsMoveConstructibleOnly::value); } TEST_CASE("IsMoveConstructibleOnly false with copy ctor", "[helpers]") { - REQUIRE_FALSE( IsMoveConstructibleOnly::value ); + REQUIRE_FALSE(IsMoveConstructibleOnly::value); } TEST_CASE("IsMoveConstructibleOnly false with move assign", "[helpers]") { - REQUIRE_FALSE( IsMoveConstructibleOnly::value ); + REQUIRE_FALSE(IsMoveConstructibleOnly::value); } TEST_CASE("IsMoveConstructibleOnly false with copy assign", "[helpers]") { - REQUIRE_FALSE( IsMoveConstructibleOnly::value ); + REQUIRE_FALSE(IsMoveConstructibleOnly::value); } TEST_CASE("IsMoveConstructibleOnly true when met", "[helpers]") { - REQUIRE( IsMoveConstructibleOnly::value ); + REQUIRE(IsMoveConstructibleOnly::value); } diff --git a/test/test_iteratoriterator.cpp b/test/test_iteratoriterator.cpp index 129ebd15..c3abd95a 100644 --- a/test/test_iteratoriterator.cpp +++ b/test/test_iteratoriterator.cpp @@ -8,49 +8,49 @@ using iter::impl::IterIterWrapper; TEST_CASE("Iterator over a vector of vector iterators", "[iteratoriterator]") { - using std::vector; - vector v = {2, 4, 6, 8}; - - IterIterWrapper::iterator>> itr; - itr.get().push_back(std::begin(v) + 1); - itr.get().push_back(std::end(v) - 1); - itr.get().push_back(std::begin(v)); - - auto it = std::begin(itr); - REQUIRE( *it == 4 ); - REQUIRE( it != std::end(itr) ); - ++it; - REQUIRE( *it == 8 ); - it++; - REQUIRE( *it == 2 ); - ++it; - REQUIRE( it == std::end(itr) ); - - REQUIRE( itr[0] == 4 ); - REQUIRE( itr[1] == 8 ); - REQUIRE( itr[2] == 2 ); - - auto rit = itr.rbegin(); - - REQUIRE( *rit == 2 ); - REQUIRE( rit != itr.rend() ); - ++rit; - REQUIRE( *rit == 8 ); - ++rit; - REQUIRE( *rit == 4 ); - ++rit; - REQUIRE( rit == itr.rend() ); + using std::vector; + vector v = {2, 4, 6, 8}; + + IterIterWrapper::iterator>> itr; + itr.get().push_back(std::begin(v) + 1); + itr.get().push_back(std::end(v) - 1); + itr.get().push_back(std::begin(v)); + + auto it = std::begin(itr); + REQUIRE(*it == 4); + REQUIRE(it != std::end(itr)); + ++it; + REQUIRE(*it == 8); + it++; + REQUIRE(*it == 2); + ++it; + REQUIRE(it == std::end(itr)); + + REQUIRE(itr[0] == 4); + REQUIRE(itr[1] == 8); + REQUIRE(itr[2] == 2); + + auto rit = itr.rbegin(); + + REQUIRE(*rit == 2); + REQUIRE(rit != itr.rend()); + ++rit; + REQUIRE(*rit == 8); + ++rit; + REQUIRE(*rit == 4); + ++rit; + REQUIRE(rit == itr.rend()); } TEST_CASE("IteratorIterator operator->", "[iteratoriterator]") { - using std::vector; - using std::string; - vector v = {"hello", "everyone"}; - IterIterWrapper::iterator>> itritr; - itritr.get().push_back(std::end(v) - 1); - itritr.get().push_back(std::begin(v)); - auto it = std::begin(itritr); - REQUIRE( it->size() == 8 ); + using std::vector; + using std::string; + vector v = {"hello", "everyone"}; + IterIterWrapper::iterator>> itritr; + itritr.get().push_back(std::end(v) - 1); + itritr.get().push_back(std::begin(v)); + auto it = std::begin(itritr); + REQUIRE(it->size() == 8); } TEST_CASE("Iterate over a vector of string iterators", "[iteratoriterator]") { @@ -58,6 +58,6 @@ TEST_CASE("Iterate over a vector of string iterators", "[iteratoriterator]") { IterIterWrapper> itritr; auto it = std::begin(itritr); static_assert(std::is_same::reference>::value, + std::iterator_traits::reference>::value, "iterator is mis marked"); } diff --git a/test/test_mixed.cpp b/test/test_mixed.cpp index f0ed106e..b9be62ff 100644 --- a/test/test_mixed.cpp +++ b/test/test_mixed.cpp @@ -1,6 +1,5 @@ // mixing different itertools, there is nothing called iter::mixed() - #include "itertools.hpp" #include "catch.hpp" @@ -9,122 +8,116 @@ #include class MyUnMovable { - int val; -public: - constexpr MyUnMovable(int val) - : val{val} - { } - - MyUnMovable(const MyUnMovable&) = delete; - MyUnMovable& operator=(const MyUnMovable&) = delete; - - MyUnMovable(MyUnMovable&& other) - : val{other.val} - { } - - constexpr int get_val() const { - return val; - } - void set_val(int val) { - this->val = val; - } - - bool operator==(const MyUnMovable& other) const { - return this->val == other.val; - } - - bool operator!=(const MyUnMovable& other) const { - return !(*this == other); - } + int val; + + public: + constexpr MyUnMovable(int val) : val{val} {} + + MyUnMovable(const MyUnMovable&) = delete; + MyUnMovable& operator=(const MyUnMovable&) = delete; + + MyUnMovable(MyUnMovable&& other) : val{other.val} {} + + constexpr int get_val() const { + return val; + } + void set_val(int val) { + this->val = val; + } + + bool operator==(const MyUnMovable& other) const { + return this->val == other.val; + } + + bool operator!=(const MyUnMovable& other) const { + return !(*this == other); + } }; namespace { - auto inc_ten = [](MyUnMovable& el) -> MyUnMovable& { - int va = el.get_val(); - el.set_val(va + 10); - return el; - }; - auto dec_ten = [](MyUnMovable& el) -> MyUnMovable& { - int va = el.get_val(); - el.set_val(va - 10); - return el; - }; + auto inc_ten = [](MyUnMovable& el) -> MyUnMovable& { + int va = el.get_val(); + el.set_val(va + 10); + return el; + }; + auto dec_ten = [](MyUnMovable& el) -> MyUnMovable& { + int va = el.get_val(); + el.set_val(va - 10); + return el; + }; } TEST_CASE("filtering doesn't dereference multiple times", "[imap][filter]") { - using iter::filter; - using iter::imap; + using iter::filter; + using iter::imap; - // source data - std::array arr = {{{41}, {42}, {43}}}; + // source data + std::array arr = {{{41}, {42}, {43}}}; - auto transformed1 = imap(inc_ten, arr); - auto filtered = filter([](const MyUnMovable& el) { - return 52 != el.get_val(); - }, transformed1); - auto transformed2 = imap(dec_ten, filtered); + auto transformed1 = imap(inc_ten, arr); + auto filtered = filter( + [](const MyUnMovable& el) { return 52 != el.get_val(); }, transformed1); + auto transformed2 = imap(dec_ten, filtered); - std::vector v; - for (auto&& el : transformed2) { - // I would use imap again instead of the loop if this wasn't an imap - // test - v.push_back(el.get_val()); - } + std::vector v; + for (auto&& el : transformed2) { + // I would use imap again instead of the loop if this wasn't an imap + // test + v.push_back(el.get_val()); + } - std::vector vc = {41, 43}; + std::vector vc = {41, 43}; - REQUIRE( v == vc); + REQUIRE(v == vc); - constexpr std::array arrc = {{{41}, {52}, {43}}}; - REQUIRE( arr == arrc ); + constexpr std::array arrc = {{{41}, {52}, {43}}}; + REQUIRE(arr == arrc); } -TEST_CASE("dropwhile doesn't dereference multiple times", "[imap][dropwhile]"){ - using iter::imap; - using iter::dropwhile; +TEST_CASE("dropwhile doesn't dereference multiple times", "[imap][dropwhile]") { + using iter::imap; + using iter::dropwhile; - std::array arr = {{{41}, {42}, {43}}}; + std::array arr = {{{41}, {42}, {43}}}; - auto transformed1 = imap(inc_ten, arr); - auto filtered = dropwhile([](const MyUnMovable& el) { - return 52 != el.get_val(); - }, transformed1); - auto transformed2 = imap(dec_ten, filtered); + auto transformed1 = imap(inc_ten, arr); + auto filtered = dropwhile( + [](const MyUnMovable& el) { return 52 != el.get_val(); }, transformed1); + auto transformed2 = imap(dec_ten, filtered); - std::vector v; - for (auto&& el : transformed2) { - v.push_back(el.get_val()); - } + std::vector v; + for (auto&& el : transformed2) { + v.push_back(el.get_val()); + } - std::vector vc = {42, 43}; + std::vector vc = {42, 43}; - std::vector vsc = {51, 42, 43}; - auto get_vals = imap([](const MyUnMovable& mv){return mv.get_val();}, arr); - std::vector vs(std::begin(get_vals), std::end(get_vals)); - REQUIRE( vs == vsc ); + std::vector vsc = {51, 42, 43}; + auto get_vals = imap([](const MyUnMovable& mv) { return mv.get_val(); }, arr); + std::vector vs(std::begin(get_vals), std::end(get_vals)); + REQUIRE(vs == vsc); } -TEST_CASE("takewhile doesn't dereference multiple times", "[imap][takewhile]"){ - using iter::imap; - using iter::takewhile; +TEST_CASE("takewhile doesn't dereference multiple times", "[imap][takewhile]") { + using iter::imap; + using iter::takewhile; - std::array arr = {{{41}, {42}, {43}}}; + std::array arr = {{{41}, {42}, {43}}}; - auto transformed1 = imap(inc_ten, arr); - auto filtered = takewhile([](const MyUnMovable& el) { - return 53 != el.get_val(); - }, transformed1); - auto transformed2 = imap(dec_ten, filtered); + auto transformed1 = imap(inc_ten, arr); + auto filtered = takewhile( + [](const MyUnMovable& el) { return 53 != el.get_val(); }, transformed1); + auto transformed2 = imap(dec_ten, filtered); - std::vector v; - for (auto&& el : transformed2) { - v.push_back(el.get_val()); - } + std::vector v; + for (auto&& el : transformed2) { + v.push_back(el.get_val()); + } - std::vector vc = {41, 42}; + std::vector vc = {41, 42}; - std::vector vsc = {41, 42, 53}; - auto get_vals = imap([](const MyUnMovable& mv){return mv.get_val();}, arr); - std::vector vs(std::begin(get_vals), std::end(get_vals)); - REQUIRE( vs == vsc ); + std::vector vsc = {41, 42, 53}; + auto get_vals = imap([](const MyUnMovable& mv) { return mv.get_val(); }, arr); + std::vector vs(std::begin(get_vals), std::end(get_vals)); + REQUIRE(vs == vsc); } diff --git a/test/test_range.cpp b/test/test_range.cpp index 887cee8b..52482df0 100644 --- a/test/test_range.cpp +++ b/test/test_range.cpp @@ -10,247 +10,247 @@ using Vec = const std::vector; using iter::range; - TEST_CASE("range: works with only stop", "[range]") { - auto r = range(5); - Vec v(std::begin(r), std::end(r)); - Vec vc{0, 1, 2, 3, 4}; + auto r = range(5); + Vec v(std::begin(r), std::end(r)); + Vec vc{0, 1, 2, 3, 4}; - REQUIRE( v == vc ); + REQUIRE(v == vc); } TEST_CASE("range: works with start and stop", "[range]") { - auto r = range(1, 5); - Vec v(std::begin(r), std::end(r)); - Vec vc {1, 2, 3, 4}; + auto r = range(1, 5); + Vec v(std::begin(r), std::end(r)); + Vec vc{1, 2, 3, 4}; - REQUIRE( v == vc ); + REQUIRE(v == vc); } TEST_CASE("range: works with positive step > 1", "[range]") { - auto r = range(1, 10, 3); - Vec v(std::begin(r), std::end(r)); - Vec vc{1, 4, 7}; + auto r = range(1, 10, 3); + Vec v(std::begin(r), std::end(r)); + Vec vc{1, 4, 7}; - REQUIRE( v == vc ); + REQUIRE(v == vc); } TEST_CASE("range(0) is empty", "[range]") { - auto r = iter::range(0); - REQUIRE( std::begin(r) == std::end(r) ); + auto r = iter::range(0); + REQUIRE(std::begin(r) == std::end(r)); } TEST_CASE("range: postfix++", "[range]") { - auto r = iter::range(3); - auto it = std::begin(r); - it++; - REQUIRE( *it == 1 ); + auto r = iter::range(3); + auto it = std::begin(r); + it++; + REQUIRE(*it == 1); } TEST_CASE("start > stop produces empty range", "[range]") { - auto r = range(5, 0); - Vec v(std::begin(r), std::end(r)); - REQUIRE( v.empty() ); + auto r = range(5, 0); + Vec v(std::begin(r), std::end(r)); + REQUIRE(v.empty()); } TEST_CASE("start < stop and step < 0 produces empty range", "[range]") { - auto r = range(0, 5, -1); - Vec v(std::begin(r), std::end(r)); - REQUIRE( v.empty() ); + auto r = range(0, 5, -1); + Vec v(std::begin(r), std::end(r)); + REQUIRE(v.empty()); } TEST_CASE("range: with only a negative stop is empty", "[range]") { - auto r = range(-3); - Vec v(std::begin(r), std::end(r)); + auto r = range(-3); + Vec v(std::begin(r), std::end(r)); - REQUIRE( v.empty() ); + REQUIRE(v.empty()); } TEST_CASE("range: works with negative step", "[range]") { - auto r = range(5, -5, -3); - Vec v(std::begin(r), std::end(r)); - Vec vc{5, 2, -1, -4}; + auto r = range(5, -5, -3); + Vec v(std::begin(r), std::end(r)); + Vec vc{5, 2, -1, -4}; - REQUIRE( v == vc ); + REQUIRE(v == vc); } TEST_CASE("range: stops short when step doesn't divide stop-start", "[range]") { - auto r = range(0, 5, 2); - Vec v(std::begin(r), std::end(r)); - Vec vc{0, 2, 4}; - - REQUIRE( v == vc ); + auto r = range(0, 5, 2); + Vec v(std::begin(r), std::end(r)); + Vec vc{0, 2, 4}; + REQUIRE(v == vc); } TEST_CASE("range: stops short when step > stop-start", "[range]") { - auto r = range(0, 10, 20); - Vec v(std::begin(r), std::end(r)); - REQUIRE( v.size() == 1 ); + auto r = range(0, 10, 20); + Vec v(std::begin(r), std::end(r)); + REQUIRE(v.size() == 1); } TEST_CASE("range: step size of 0 gives an empty range", "[range]") { - auto r = range(0, 10, 0); - REQUIRE( std::begin(r) == std::end(r) ); - auto r2 = range(0, -10, 0); - REQUIRE( std::begin(r2) == std::end(r2) ); + auto r = range(0, 10, 0); + REQUIRE(std::begin(r) == std::end(r)); + auto r2 = range(0, -10, 0); + REQUIRE(std::begin(r2) == std::end(r2)); } TEST_CASE("range: can create constexpr ranges", "[range]") { - constexpr auto r = range(10); (void)r; - constexpr auto r2 = range(4, 10); (void)r2; - constexpr auto r3 = range(4, 10, 2); (void)r3; - - constexpr auto it = r2.begin(); // std::begin isn't constexpr - constexpr auto i = *it; - static_assert(i == 4, "range's begin has the wrong value"); - - constexpr auto rf = range(10.0); - constexpr auto itf = rf.begin(); - constexpr auto f = *itf; - static_assert(f == 0.0, "range's begin has tho wrong value (float)"); + constexpr auto r = range(10); + (void)r; + constexpr auto r2 = range(4, 10); + (void)r2; + constexpr auto r3 = range(4, 10, 2); + (void)r3; + + constexpr auto it = r2.begin(); // std::begin isn't constexpr + constexpr auto i = *it; + static_assert(i == 4, "range's begin has the wrong value"); + + constexpr auto rf = range(10.0); + constexpr auto itf = rf.begin(); + constexpr auto f = *itf; + static_assert(f == 0.0, "range's begin has tho wrong value (float)"); } TEST_CASE("range: works with a variable start, stop, and step", "[range]") { - constexpr int a = 10; - constexpr int b = 100; - constexpr int c = 50; - SECTION("Going up works") { - auto r = range(a, a+2); - Vec v(std::begin(r), std::end(r)); - Vec vc{a, a+1}; - REQUIRE( v == vc ); - } - - SECTION("Going down works") { - auto r = range(a+2, a, -1); - Vec v(std::begin(r), std::end(r)); - Vec vc{a+2, a+1}; - REQUIRE( v == vc ); - } - - SECTION("Going down with -2 stop works") { - auto r = range(a+4, a, -2); - Vec v(std::begin(r), std::end(r)); - Vec vc{a+4, a+2}; - REQUIRE( v == vc ); - } - - SECTION("Using three variable") { - auto r = range(a, b, c); - Vec v(std::begin(r), std::end(r)); - REQUIRE( std::find(std::begin(v), std::end(v), a) != std::end(v) ); - REQUIRE( std::find(std::begin(v), std::end(v), b) == std::end(v) ); - REQUIRE( v.size() == 2 ); - } - - SECTION("Using three with a unary negate on step") { - auto r = range(b, a, -c); - Vec v(std::begin(r), std::end(r)); - - REQUIRE( std::find(std::begin(v), std::end(v), b) != std::end(v) ); - REQUIRE( std::find(std::begin(v), std::end(v), a) == std::end(v) ); - REQUIRE( v.size() == 2 ); - } - - SECTION("Using all three negated") { - auto r = range(-a, -b, -c); - Vec v(std::begin(r), std::end(r)); - - REQUIRE( std::find(std::begin(v), std::end(v), -a) != std::end(v) ); - REQUIRE( std::find(std::begin(v), std::end(v), -b) == std::end(v) ); - REQUIRE( v.size() == 2 ); - } + constexpr int a = 10; + constexpr int b = 100; + constexpr int c = 50; + SECTION("Going up works") { + auto r = range(a, a + 2); + Vec v(std::begin(r), std::end(r)); + Vec vc{a, a + 1}; + REQUIRE(v == vc); + } + + SECTION("Going down works") { + auto r = range(a + 2, a, -1); + Vec v(std::begin(r), std::end(r)); + Vec vc{a + 2, a + 1}; + REQUIRE(v == vc); + } + + SECTION("Going down with -2 stop works") { + auto r = range(a + 4, a, -2); + Vec v(std::begin(r), std::end(r)); + Vec vc{a + 4, a + 2}; + REQUIRE(v == vc); + } + + SECTION("Using three variable") { + auto r = range(a, b, c); + Vec v(std::begin(r), std::end(r)); + REQUIRE(std::find(std::begin(v), std::end(v), a) != std::end(v)); + REQUIRE(std::find(std::begin(v), std::end(v), b) == std::end(v)); + REQUIRE(v.size() == 2); + } + + SECTION("Using three with a unary negate on step") { + auto r = range(b, a, -c); + Vec v(std::begin(r), std::end(r)); + + REQUIRE(std::find(std::begin(v), std::end(v), b) != std::end(v)); + REQUIRE(std::find(std::begin(v), std::end(v), a) == std::end(v)); + REQUIRE(v.size() == 2); + } + + SECTION("Using all three negated") { + auto r = range(-a, -b, -c); + Vec v(std::begin(r), std::end(r)); + REQUIRE(std::find(std::begin(v), std::end(v), -a) != std::end(v)); + REQUIRE(std::find(std::begin(v), std::end(v), -b) == std::end(v)); + REQUIRE(v.size() == 2); + } } TEST_CASE("range: forward iterator checks", "[range]") { auto r = range(10); - REQUIRE( std::end(r) == std::end(r) ); + REQUIRE(std::end(r) == std::end(r)); auto it1 = std::begin(r); auto it2 = std::begin(r); - REQUIRE_FALSE( it1 != it2 ); - REQUIRE( it1 == it2 ); + REQUIRE_FALSE(it1 != it2); + REQUIRE(it1 == it2); ++it1; - REQUIRE( it1 != it2 ); + REQUIRE(it1 != it2); ++it2; - REQUIRE( it1 == it2 ); + REQUIRE(it1 == it2); auto it3 = it1++; - REQUIRE( it3 == it2 ); + REQUIRE(it3 == it2); auto it4 = ++it3; - REQUIRE( it4 == it3 ); + REQUIRE(it4 == it3); auto it5 = std::begin(r); const auto& v = *it5; ++it5; - REQUIRE( v != *it5 ); + REQUIRE(v != *it5); } TEST_CASE("range: forward iterator with double, checks", "[range]") { auto r = range(10.0); - REQUIRE( std::end(r) == std::end(r) ); + REQUIRE(std::end(r) == std::end(r)); auto it1 = std::begin(r); auto it2 = std::begin(r); - REQUIRE_FALSE( it1 != it2 ); - REQUIRE( it1 == it2 ); + REQUIRE_FALSE(it1 != it2); + REQUIRE(it1 == it2); ++it1; - REQUIRE( it1 != it2 ); + REQUIRE(it1 != it2); ++it2; - REQUIRE( it1 == it2 ); + REQUIRE(it1 == it2); auto it3 = it1++; - REQUIRE( it3 == it2 ); + REQUIRE(it3 == it2); auto it4 = ++it3; - REQUIRE( it4 == it3 ); + REQUIRE(it4 == it3); } using FVec = const std::vector; TEST_CASE("range: using doubles", "[range]") { - auto r = range(5.0); - FVec fv(std::begin(r), std::end(r)); - FVec fvc = {0.0, 1.0, 2.0, 3.0, 4.0}; - REQUIRE( fv == fvc ); + auto r = range(5.0); + FVec fv(std::begin(r), std::end(r)); + FVec fvc = {0.0, 1.0, 2.0, 3.0, 4.0}; + REQUIRE(fv == fvc); } TEST_CASE("range: using doubles with start and stop", "[range]") { - auto r = range(5.0, 10.0); - FVec fv(std::begin(r), std::end(r)); - FVec fvc = {5.0, 6.0, 7.0, 8.0, 9.0}; - REQUIRE( fv == fvc ); + auto r = range(5.0, 10.0); + FVec fv(std::begin(r), std::end(r)); + FVec fvc = {5.0, 6.0, 7.0, 8.0, 9.0}; + REQUIRE(fv == fvc); } TEST_CASE("range: using doubles with start, stop and step", "[range]") { - auto r = range(1.0, 4.0, 0.5); - FVec fv(std::begin(r), std::end(r)); - FVec fvc = {1.0, 1.5, 2.0, 2.5, 3.0, 3.5}; - REQUIRE( fv == fvc ); + auto r = range(1.0, 4.0, 0.5); + FVec fv(std::begin(r), std::end(r)); + FVec fvc = {1.0, 1.5, 2.0, 2.5, 3.0, 3.5}; + REQUIRE(fv == fvc); } TEST_CASE("range: using doubles with negative", "[range]") { - auto r = range(0.5, -2.0, -0.5); - FVec fv(std::begin(r), std::end(r)); - FVec fvc = {0.5, 0.0, -0.5, -1.0, -1.5}; - REQUIRE( fv == fvc ); + auto r = range(0.5, -2.0, -0.5); + FVec fv(std::begin(r), std::end(r)); + FVec fvc = {0.5, 0.0, -0.5, -1.0, -1.5}; + REQUIRE(fv == fvc); } TEST_CASE("range: using doubles with uneven step", "[range]") { - auto r = range(0.0, 1.75, 0.5); - FVec fv(std::begin(r), std::end(r)); - FVec fvc = {0.0, 0.5, 1.0, 1.5}; - REQUIRE( fv == fvc ); + auto r = range(0.0, 1.75, 0.5); + FVec fv(std::begin(r), std::end(r)); + FVec fvc = {0.0, 0.5, 1.0, 1.5}; + REQUIRE(fv == fvc); } TEST_CASE("range: using doubles detects empty ranges", "[range]") { - auto r1 = range(0.0, -1.0); - REQUIRE(std::begin(r1) == std::end(r1)); + auto r1 = range(0.0, -1.0); + REQUIRE(std::begin(r1) == std::end(r1)); - auto r2 = range(0.0, 1.0, -1.0); - REQUIRE(std::begin(r2) == std::end(r2)); + auto r2 = range(0.0, 1.0, -1.0); + REQUIRE(std::begin(r2) == std::end(r2)); } TEST_CASE("range: iterator meets forward iterator requirements", "[range]") { - auto r = range(5); - auto r2 = range(5.0); - REQUIRE( itertest::IsForwardIterator::value ); - REQUIRE( itertest::IsForwardIterator::value ); + auto r = range(5); + auto r2 = range(5.0); + REQUIRE(itertest::IsForwardIterator::value); + REQUIRE(itertest::IsForwardIterator::value); } From e58ae12670ead4152fd2299d6d12857c561b6c4c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 6 Sep 2015 23:55:20 -0700 Subject: [PATCH 1343/1866] uses array ref instead of array --- test/test_chain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_chain.cpp b/test/test_chain.cpp index 85844900..c0d319d4 100644 --- a/test/test_chain.cpp +++ b/test/test_chain.cpp @@ -152,7 +152,7 @@ TEST_CASE("chain: iterator meets requirements", "[chain]") { template using ImpT = decltype(chain(std::declval()...)); TEST_CASE("chain: has correct ctor and assign ops", "[chain]") { - using T = ImpT, char[10]>; + using T = ImpT, char (&)[10]>; REQUIRE(itertest::IsMoveConstructibleOnly::value); } From 93c032eeaeda416d43e5b5b396200e9ff7c014a3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 7 Sep 2015 12:01:48 -0700 Subject: [PATCH 1344/1866] 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 From a09a2ddd0dc295e81a2406efed99a7565d850a0a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 7 Sep 2015 12:07:26 -0700 Subject: [PATCH 1345/1866] 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 44b779cc..a3451bf4 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -63,6 +63,7 @@ namespace iter { template struct ArrowHelper { using type = void; + void operator()(T&) const noexcept { } }; template From 021676994ff6bed9bcb8dcf3340fc584d34dd0e9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 7 Sep 2015 13:11:28 -0700 Subject: [PATCH 1346/1866] marks group move ctor noexcept --- groupby.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/groupby.hpp b/groupby.hpp index d794d70d..78340416 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -192,7 +192,7 @@ class iter::impl::GroupProducer { } // move-constructible, non-copy-constructible, non-assignable - Group(Group&& other) + Group(Group&& other) noexcept : owner(other.owner), key{other.key}, completed{other.completed} { other.completed = true; } From ed047ea929668c1eee53aee3c71d3de3beb676b6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 7 Sep 2015 22:00:23 -0700 Subject: [PATCH 1347/1866] fixes clang tidy warnings --- accumulate.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index eca67cb1..e82eb117 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -48,7 +48,7 @@ class iter::impl::Accumulator { accumulate_func(in_accumulate_func) {} public: - Accumulator(Accumulator&&) = default; + Accumulator(Accumulator&&) noexcept = default; class Iterator : public std::iterator { private: @@ -73,7 +73,7 @@ class iter::impl::Accumulator { acc_val{other.acc_val ? new AccumVal(*other.acc_val) : nullptr} {} Iterator& operator=(const Iterator& other) { - if (this == &other) return *this; + if (this == &other) { return *this; } this->sub_iter = other.sub_iter; this->sub_end = other.sub_end; this->accumulate_func = other.accumulate_func; @@ -82,8 +82,8 @@ class iter::impl::Accumulator { return *this; } - Iterator(Iterator&&) = default; - Iterator& operator=(Iterator&&) = default; + Iterator(Iterator&&) noexcept = default; + Iterator& operator=(Iterator&&) noexcept = default; const AccumVal& operator*() const { return *this->acc_val; From ecb00003325bd528d5e0c7d675f654d7a08376d8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 7 Sep 2015 22:00:28 -0700 Subject: [PATCH 1348/1866] fixes clang tidy warnings --- chain.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/chain.hpp b/chain.hpp index 5ee3bcfa..b61bfe68 100644 --- a/chain.hpp +++ b/chain.hpp @@ -46,7 +46,7 @@ class iter::impl::Chained { rest_chained{std::forward(rest)...} {} public: - Chained(Chained&&) = default; + Chained(Chained&&) noexcept = default; class Iterator : public std::iterator> { private: @@ -123,7 +123,7 @@ class iter::impl::Chained { : container(std::forward(in_container)) {} public: - Chained(Chained&&) = default; + Chained(Chained&&) noexcept = default; class Iterator : public std::iterator> { private: @@ -181,7 +181,7 @@ class iter::impl::ChainedFromIterable { : container(std::forward(in_container)) {} public: - ChainedFromIterable(ChainedFromIterable&&) = default; + ChainedFromIterable(ChainedFromIterable&&) noexcept = default; class Iterator : public std::iterator>> { private: @@ -231,7 +231,7 @@ class iter::impl::ChainedFromIterable { sub_end_p{clone_sub_pointer(other.sub_end_p.get())} {} Iterator& operator=(const Iterator& other) { - if (this == &other) return *this; + if (this == &other) { return *this; } this->top_level_iter = other.top_level_iter; this->top_level_end = other.top_level_end; @@ -241,8 +241,8 @@ class iter::impl::ChainedFromIterable { return *this; } - Iterator(Iterator&&) = default; - Iterator& operator=(Iterator&&) = default; + Iterator(Iterator&&) noexcept = default; + Iterator& operator=(Iterator&&) noexcept = default; ~Iterator() = default; Iterator& operator++() { From d9bbbe07ba05e33479c7ddee3048057e42373679 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 7 Sep 2015 22:14:41 -0700 Subject: [PATCH 1349/1866] undoes clang-tidy noexcept fixes they're actually just inferred noexcept, which is better --- accumulate.hpp | 2 +- chain.hpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index e82eb117..fdde9a64 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -48,7 +48,7 @@ class iter::impl::Accumulator { accumulate_func(in_accumulate_func) {} public: - Accumulator(Accumulator&&) noexcept = default; + Accumulator(Accumulator&&) = default; class Iterator : public std::iterator { private: diff --git a/chain.hpp b/chain.hpp index b61bfe68..fe30255d 100644 --- a/chain.hpp +++ b/chain.hpp @@ -46,7 +46,7 @@ class iter::impl::Chained { rest_chained{std::forward(rest)...} {} public: - Chained(Chained&&) noexcept = default; + Chained(Chained&&) = default; class Iterator : public std::iterator> { private: @@ -123,7 +123,7 @@ class iter::impl::Chained { : container(std::forward(in_container)) {} public: - Chained(Chained&&) noexcept = default; + Chained(Chained&&) = default; class Iterator : public std::iterator> { private: @@ -181,7 +181,7 @@ class iter::impl::ChainedFromIterable { : container(std::forward(in_container)) {} public: - ChainedFromIterable(ChainedFromIterable&&) noexcept = default; + ChainedFromIterable(ChainedFromIterable&&) = default; class Iterator : public std::iterator>> { private: @@ -241,8 +241,8 @@ class iter::impl::ChainedFromIterable { return *this; } - Iterator(Iterator&&) noexcept = default; - Iterator& operator=(Iterator&&) noexcept = default; + Iterator(Iterator&&) = default; + Iterator& operator=(Iterator&&) = default; ~Iterator() = default; Iterator& operator++() { From 5f50142941b982f4c6fcf18b3f7ab65d00193395 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 7 Sep 2015 22:17:46 -0700 Subject: [PATCH 1350/1866] adds braces around if body --- groupby.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/groupby.hpp b/groupby.hpp index 78340416..d8e79d0b 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -81,7 +81,7 @@ class iter::impl::GroupProducer { key_func{other.key_func} {} Iterator& operator=(const Iterator& other) { - if (this == &other) return *this; + if (this == &other) { return *this; } this->sub_iter = other.sub_iter; this->sub_end = other.sub_end; this->item = other.item; From 445d734a5da094bde0caaab22509ae6956b814c3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 7 Sep 2015 22:19:43 -0700 Subject: [PATCH 1351/1866] fixes clang-tidy warnings --- range.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/range.hpp b/range.hpp index 74d6bc5d..67a0c267 100644 --- a/range.hpp +++ b/range.hpp @@ -68,7 +68,7 @@ namespace iter { T start_{}; T value_{}; T step_{}; - unsigned long steps_taken{}; + std::size_t steps_taken{}; public: constexpr RangeIterData() noexcept = default; @@ -162,9 +162,8 @@ class iter::impl::Range { const Iterator& lhs, const Iterator& rhs) noexcept { if (rhs.is_end) { return not_equal_to_impl(lhs, rhs, std::is_unsigned{}); - } else { - return not_equal_to_impl(rhs, lhs, std::is_unsigned{}); } + return not_equal_to_impl(rhs, lhs, std::is_unsigned{}); } public: From 7bd394a3228e3a0fbdf826c46f5c85dd6d8f62a4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 7 Sep 2015 22:21:31 -0700 Subject: [PATCH 1352/1866] adds braces around if body --- sliding_window.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sliding_window.hpp b/sliding_window.hpp index cffc0e0f..11b633d1 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -55,7 +55,7 @@ class iter::impl::WindowSlider { while (i < window_sz && this->sub_iter != in_end) { this->window.get().push_back(this->sub_iter); ++i; - if (i != window_sz) ++this->sub_iter; + if (i != window_sz) { ++this->sub_iter; } } } From eb3b7042000ad2e4e9944cb83f78e1b0b2bd88f2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 7 Sep 2015 22:22:11 -0700 Subject: [PATCH 1353/1866] removes else after return --- unique_everseen.hpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/unique_everseen.hpp b/unique_everseen.hpp index 5a993304..8be77d85 100644 --- a/unique_everseen.hpp +++ b/unique_everseen.hpp @@ -27,9 +27,8 @@ namespace iter { if (elem_seen.find(e) == std::end(elem_seen)) { elem_seen.insert(e); return true; - } else { - return false; } + return false; }; return filter(func, std::forward(container)); } @@ -42,9 +41,8 @@ namespace iter { if (elem_seen.find(e) == std::end(elem_seen)) { elem_seen.insert(e); return true; - } else { - return false; } + return false; }; return filter(func, il); } From 16f5868e4a77660ae3b3317fb50fefaed206f53f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 7 Sep 2015 22:25:44 -0700 Subject: [PATCH 1354/1866] removes else after return --- zip_longest.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/zip_longest.hpp b/zip_longest.hpp index dcd9ec59..e0566ea4 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -88,9 +88,8 @@ class iter::impl::ZippedLongest { 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 std::tuple_cat(std::tuple{{}}, *this->rest_iter); } ArrowProxy operator->() { From 0cbab1df0403c154e04e520639fc4dd559d4ca85 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 8 Sep 2015 20:49:03 -0700 Subject: [PATCH 1355/1866] uses make_shared in powerset --- powerset.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/powerset.hpp b/powerset.hpp index 83e7ebe4..b79c2c96 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -54,7 +54,8 @@ class iter::impl::Powersetter { 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)} {} @@ -62,8 +63,8 @@ class iter::impl::Powersetter { ++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 b4160e48ddf29a998a7c8ceea0dd15140828953b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 8 Sep 2015 22:17:10 -0700 Subject: [PATCH 1356/1866] tests iterbase implementation functionality --- test/test_iterbase.cpp | 97 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 test/test_iterbase.cpp diff --git a/test/test_iterbase.cpp b/test/test_iterbase.cpp new file mode 100644 index 00000000..95122697 --- /dev/null +++ b/test/test_iterbase.cpp @@ -0,0 +1,97 @@ +// AGAIN the contents of iterbase are completely subject to change, do not rely +// on any of this. Users of the library must consider all of this undocumented +// + +#include +#include +#include +#include +#include +#include +#include + +#include "catch.hpp" +#include "helpers.hpp" + +namespace it = iter::impl; + +using IVec = std::vector; + +template +using hrai = it::has_random_access_iter; +TEST_CASE("Detects random access iterators correctly", "[iterbase]") { + REQUIRE(hrai>::value); + REQUIRE(hrai::value); + REQUIRE(hrai::value); + + REQUIRE_FALSE(hrai>::value); + REQUIRE_FALSE(hrai{}))>::value); + REQUIRE_FALSE(hrai>::value); +} + +TEST_CASE("Detects correct iterator types", "[iterbase]") { + REQUIRE((std::is_same, IVec::iterator>::value)); + REQUIRE((std::is_same, IVec::iterator>::value)); + REQUIRE((std::is_same, + IVec::iterator::reference>::value)); + REQUIRE((std::is_same, + IVec::iterator::reference>::value)); + REQUIRE((std::is_same, + IVec::iterator::value_type>::value)); + + REQUIRE((std::is_same, + IVec::reverse_iterator>::value)); + REQUIRE((std::is_same, + IVec::reverse_iterator::reference>::value)); + REQUIRE( + (std::is_same, IVec::iterator::pointer>::value)); + REQUIRE((std::is_same, int*>::value)); + REQUIRE((std::is_same, + IVec::reverse_iterator::pointer>::value)); +} + +TEST_CASE("advance, next, size", "[iterbase]") { + IVec v = {2, 4, 6, 8, 10, 12, 14, 16, 18}; + auto itr = std::begin(v); + REQUIRE(it::apply_arrow(itr) == &v[0]); + + it::dumb_advance(itr, 3); + REQUIRE(itr == (std::begin(v) + 3)); + REQUIRE(it::dumb_next(std::begin(v), 3) == std::begin(v) + 3); + REQUIRE(it::dumb_size(v) == v.size()); +} + +TEST_CASE("are_same", "[iterbase]") { + REQUIRE((it::are_same::value)); + REQUIRE_FALSE((it::are_same::value)); + REQUIRE_FALSE((it::are_same::value)); + REQUIRE_FALSE((it::are_same::value)); +} + +TEST_CASE("DerefHolder lvalue reference", "[iterbase]") { + it::DerefHolder dh; + int a = 2; + int b = 5; + REQUIRE_FALSE(dh); + dh.reset(a); + REQUIRE(dh); + + REQUIRE(dh.get_ptr() == &a); + REQUIRE(&dh.get() == &a); + dh.reset(b); + REQUIRE(dh.get_ptr() == &b); + REQUIRE(&dh.get() == &b); +} + +TEST_CASE("DerefHolder non-reference", "[iterbase]") { + it::DerefHolder dh; + int a = 2; + int b = 5; + REQUIRE_FALSE(dh); + dh.reset(std::move(a)); + REQUIRE(dh.get() == 2); + REQUIRE(&dh.get() != &a); + + dh.reset(std::move(b)); + REQUIRE(dh.get() == 5); +} From 90f30dbc528d1dce3926aa2e1ac145b7c1fb1267 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 8 Sep 2015 22:19:04 -0700 Subject: [PATCH 1357/1866] adds iterbase test, removes explicit CXX in scons --- test/SConstruct | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/SConstruct b/test/SConstruct index 129c2dbf..d9513f5f 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -2,12 +2,11 @@ import os env = Environment( ENV = os.environ, - CXX='c++', CXXFLAGS= ['-g', '-Wall', '-Wextra', '-pedantic', '-std=c++11', '-I/usr/local/include', '-I.'], CPPPATH='..', - LINKFLAGS='-L/usr/local/lib') + LINKFLAGS=['-L/usr/local/lib']) # allows highighting to print to terminal from compiler output env['ENV']['TERM'] = os.environ['TERM'] @@ -43,6 +42,7 @@ progs = Split( zip iteratoriterator + iterbase mixed helpers ''' From b285ed2d4aff37009fb3c05bd3de2f3c50308f38 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 8 Sep 2015 22:20:25 -0700 Subject: [PATCH 1358/1866] simplifies derefholder, fixes operator bool I needed to static_cast the unique_ptr.. --- internal/iterbase.hpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index a3451bf4..fc344137 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -63,7 +63,7 @@ namespace iter { template struct ArrowHelper { using type = void; - void operator()(T&) const noexcept { } + void operator()(T&) const noexcept {} }; template @@ -202,8 +202,7 @@ namespace iter { // get() returns a reference to the held item // get_ptr() returns a pointer to the held item // reset() replaces the currently held item - - template + template class DerefHolder { private: static_assert(!std::is_lvalue_reference::value, @@ -244,18 +243,16 @@ namespace iter { } explicit operator bool() const { - return this->item_p; + return static_cast(this->item_p); } }; - // Specialization for when T is an lvalue ref. Keep this in mind - // wherever a T appears. + // Specialization for when T is an lvalue ref template - class DerefHolder::value>::type> { + class DerefHolder { public: - using reference = T; - using pointer = typename std::remove_reference::type*; + using reference = T&; + using pointer = T*; private: pointer item_p{}; @@ -271,7 +268,7 @@ namespace iter { return this->item_p; } - void reset(T item) { + void reset(reference item) { this->item_p = &item; } From a9c719a7fa8e65a076aaa9b0c6c17194810156c0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 8 Sep 2015 22:31:53 -0700 Subject: [PATCH 1359/1866] removes noexcept from accum iterator move --- accumulate.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index fdde9a64..6d336e2c 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -82,8 +82,8 @@ class iter::impl::Accumulator { return *this; } - Iterator(Iterator&&) noexcept = default; - Iterator& operator=(Iterator&&) noexcept = default; + Iterator(Iterator&&) = default; + Iterator& operator=(Iterator&&) = default; const AccumVal& operator*() const { return *this->acc_val; From cea0bf753f59a7fbd938bb8cc7c628d01c2712bb Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Fri, 18 Sep 2015 18:02:28 -0700 Subject: [PATCH 1360/1866] tests that filter drops nullptrs by identity --- test/test_filter.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/test_filter.cpp b/test/test_filter.cpp index 28ac6938..c6dc58ec 100644 --- a/test/test_filter.cpp +++ b/test/test_filter.cpp @@ -70,6 +70,17 @@ TEST_CASE("filter: using identity", "[filter]") { REQUIRE(v == vc); } +TEST_CASE("filter: skips null pointers", "[filter]") { + int a = 1; + int b = 2; + const std::vector ns = {0, &a, nullptr, nullptr, &b, nullptr}; + + auto f = filter(ns); + const std::vector v(std::begin(f), std::end(f)); + const std::vector vc = {&a, &b}; + REQUIRE( v == vc ); +} + TEST_CASE("filter: binds to lvalues, moves rvales", "[filter]") { itertest::BasicIterable bi{1, 2, 3, 4}; From ec84a613c4d08e5214fbcad8b9c24fe92f22c2f0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 27 Mar 2016 20:16:07 -0700 Subject: [PATCH 1361/1866] Removes development status notes from README --- README.md | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/README.md b/README.md index 7cadd713..dd55604e 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,5 @@ -CPPItertools C++14 development Branch +CPPItertools ============ - -**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 7a872f9e3c37401bb98c0b44a56934381914770e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 27 Mar 2016 20:38:54 -0700 Subject: [PATCH 1362/1866] uses callable struct instead of functions --- enumerate.hpp | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 715eb7b0..f104b6eb 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -13,14 +13,8 @@ namespace iter { namespace impl { template class Enumerable; + struct EnumerateFn; } - - template - impl::Enumerable enumerate(Container&&, std::size_t = 0); - - template - impl::Enumerable> enumerate( - std::initializer_list, std::size_t = 0); } template @@ -29,12 +23,7 @@ class iter::impl::Enumerable { Container container; const std::size_t start; - // The only thing allowed to directly instantiate an Enumerable is - // the enumerate function - friend Enumerable iter::enumerate(Container&&, std::size_t); - template - friend Enumerable> iter::enumerate( - std::initializer_list, std::size_t); + friend struct EnumerateFn; // for IterYield using BasePair = std::pair>; @@ -105,16 +94,22 @@ class iter::impl::Enumerable { } }; -template -iter::impl::Enumerable iter::enumerate( - Container&& container, std::size_t start) { - return {std::forward(container), start}; -} +struct iter::impl::EnumerateFn { + template + Enumerable operator()( + Container&& container, std::size_t start=0) const { + return {std::forward(container), start}; + } -template -iter::impl::Enumerable> iter::enumerate( - std::initializer_list il, std::size_t start) { - return {std::move(il), start}; + template + Enumerable> operator()( + std::initializer_list il, std::size_t start=0) const { + return {std::move(il), start}; + } +}; + +namespace iter { +constexpr impl::EnumerateFn enumerate; } #endif From fa2eb57bf8142b9a94c86d70a3597e6b6b42aec7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 1 Apr 2016 19:53:20 -0700 Subject: [PATCH 1363/1866] Replaces filter() functions with FilterFn class --- filter.hpp | 82 ++++++++++++++++++++++++------------------------------ 1 file changed, 37 insertions(+), 45 deletions(-) diff --git a/filter.hpp b/filter.hpp index e899b80b..041b73c5 100644 --- a/filter.hpp +++ b/filter.hpp @@ -11,14 +11,9 @@ namespace iter { namespace impl { template class Filtered; - } - - template - impl::Filtered filter(FilterFunc, Container&&); - template - impl::Filtered> filter( - FilterFunc, std::initializer_list); + class FilterFn; + } } template @@ -27,12 +22,7 @@ class iter::impl::Filtered { Container container; FilterFunc filter_func; - // The filter function is the only thing allowed to create a Filtered - friend Filtered iter::filter(FilterFunc, Container&&); - - template - friend Filtered> iter::filter( - FF, std::initializer_list); + friend class FilterFn; // Value constructor for use only in the filter function Filtered(FilterFunc in_filter_func, Container&& in_container) @@ -117,46 +107,48 @@ class iter::impl::Filtered { } }; -template -iter::impl::Filtered iter::filter( - FilterFunc filter_func, Container&& container) { - return {filter_func, std::forward(container)}; -} - -template -iter::impl::Filtered> iter::filter( - FilterFunc filter_func, std::initializer_list il) { - return {filter_func, std::move(il)}; -} - -namespace iter { - namespace detail { +class iter::impl::FilterFn { + public: + template + iter::impl::Filtered operator()( + FilterFunc filter_func, Container&& container) const { + return {std::move(filter_func), std::forward(container)}; + } - template - bool boolean_cast(const T& t) { - return bool(t); - } + template + iter::impl::Filtered> operator()( + FilterFunc filter_func, std::initializer_list il) const { + return {std::move(filter_func), std::move(il)}; + } - template - class BoolTester { - public: - bool operator()(const impl::iterator_deref item) const { - return bool(item); - } - }; + template >> + auto operator()(Container&& container) const { + return (*this)(BoolTester{}, std::forward(container)); } - template - auto filter(Container&& container) { - return filter( - detail::BoolTester(), std::forward(container)); + template + auto operator()(std::initializer_list il) const { + return (*this)(BoolTester>{}, std::move(il)); } + private: template - auto filter(std::initializer_list il) { - return filter( - detail::BoolTester>(), std::move(il)); + bool boolean_cast(const T& t) { + return bool(t); } + + template + class BoolTester { + public: + bool operator()(const impl::iterator_deref item) const { + return bool(item); + } + }; +}; + +namespace iter { + constexpr impl::FilterFn filter{}; } #endif From 6bde3578abc84a071bcca85156fe1b7d48d4e5a4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 1 Apr 2016 19:56:21 -0700 Subject: [PATCH 1364/1866] tests filter with predicate and pipe --- test/test_filter.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/test_filter.cpp b/test/test_filter.cpp index c6dc58ec..6e391245 100644 --- a/test/test_filter.cpp +++ b/test/test_filter.cpp @@ -127,6 +127,15 @@ TEST_CASE("filter: doesn't move or copy elements of iterable", "[filter]") { } } +TEST_CASE("filter: works with pipe", "[filter]") { + Vec ns = {1, 2, 5, 6, 3, 1, 7, -1, 5}; + Vec vc = {1, 2, 3, 1, -1}; + + auto f = ns | filter(LessThanValue{5}); + Vec v(std::begin(f), std::end(f)); + REQUIRE(v == vc); +} + TEST_CASE("filter: iterator meets requirements", "[filter]") { std::string s{}; auto c = filter([] { return true; }, s); From 6f53bda39893a29942f2fecbb7612c38fb8cbff6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 1 Apr 2016 19:56:36 -0700 Subject: [PATCH 1365/1866] supports seq | filter(predicate) --- filter.hpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/filter.hpp b/filter.hpp index 041b73c5..fa943bf4 100644 --- a/filter.hpp +++ b/filter.hpp @@ -132,6 +132,22 @@ class iter::impl::FilterFn { return (*this)(BoolTester>{}, std::move(il)); } + template + struct FilterFnPartial : Pipeable> { + FilterFnPartial(FilterFunc f) : fun(std::move(f)) {} + template + auto operator()(Container&& container) const { + return FilterFn{}(fun, std::forward(container)); + } + private: + FilterFunc fun; + }; + + template >> + FilterFnPartial operator()(FilterFunc filter_func) const { + return {filter_func}; + } + private: template bool boolean_cast(const T& t) { From b33570172d49fe896baecc20b76ac14a9a75683f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 1 Apr 2016 19:58:39 -0700 Subject: [PATCH 1366/1866] supports seq | filter without predicate --- filter.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/filter.hpp b/filter.hpp index fa943bf4..6ea9c0f8 100644 --- a/filter.hpp +++ b/filter.hpp @@ -107,7 +107,7 @@ class iter::impl::Filtered { } }; -class iter::impl::FilterFn { +class iter::impl::FilterFn : public iter::impl::Pipeable { public: template iter::impl::Filtered operator()( From 06c528d1e941e3c70b61327f405b191ae7a86cc8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 1 Apr 2016 19:59:03 -0700 Subject: [PATCH 1367/1866] tests filter with pipe and no predicate --- test/test_filter.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/test_filter.cpp b/test/test_filter.cpp index 6e391245..cc68f616 100644 --- a/test/test_filter.cpp +++ b/test/test_filter.cpp @@ -136,6 +136,16 @@ TEST_CASE("filter: works with pipe", "[filter]") { REQUIRE(v == vc); } +TEST_CASE("filter: using identity and pipe", "[filter]") { + Vec ns{0, 1, 2, 0, 3, 0, 0, 0, 4, 5, 0}; + auto f = ns | filter; + Vec v(std::begin(f), std::end(f)); + + Vec vc = {1, 2, 3, 4, 5}; + REQUIRE(v == vc); +} + + TEST_CASE("filter: iterator meets requirements", "[filter]") { std::string s{}; auto c = filter([] { return true; }, s); From 55d272ffdee8a8af84884d63b87f72c3534fd792 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 3 Apr 2016 18:30:10 -0700 Subject: [PATCH 1368/1866] supports seq | enumerate --- enumerate.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enumerate.hpp b/enumerate.hpp index f104b6eb..1c4fb666 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -94,7 +94,7 @@ class iter::impl::Enumerable { } }; -struct iter::impl::EnumerateFn { +struct iter::impl::EnumerateFn : iter::impl::Pipeable { template Enumerable operator()( Container&& container, std::size_t start=0) const { From 2be398391594b47ea5868ed713dba88f1e5e12fd Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 3 Apr 2016 18:31:22 -0700 Subject: [PATCH 1369/1866] adds IsIterable trait and Pipeable helper I should've done these last few commits in a different order. IsIterable is true if T is an iterable (it can be passed to std::begin()). Pipeable is a helper to allow the sequence to be passed after the pipe. seq | iter::fun vs iter::fun(seq) --- internal/iterbase.hpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index 20d0fc39..afa9d0fd 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -50,6 +50,16 @@ namespace iter { using iterator_traits_deref = std::remove_reference_t>; + template + struct IsIterable : std::false_type {}; + + // Assuming that if a type works with std::begin, it is an iterable. + template + struct IsIterable>> : std::true_type{}; + + template + constexpr bool is_iterable = IsIterable::value; + namespace detail { template struct ArrowHelper { @@ -315,6 +325,18 @@ namespace iter { return this->item_p != nullptr; } }; + + // allows f(x) to be 'called' as x | f + // let the record show I dislike adding yet another syntactical mess to + // this clown car of a language. + template + struct Pipeable { + template + friend decltype(auto) operator|(T&& x, const Pipeable& p) { + return static_cast(p)(std::forward(x)); + } + }; + } } From 60d201da11bdd86b87628613b5a780215be13365 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 3 Apr 2016 18:35:00 -0700 Subject: [PATCH 1370/1866] tests that enumerate works with pipe --- test/test_enumerate.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/test_enumerate.cpp b/test/test_enumerate.cpp index 778cce39..38b3a90a 100644 --- a/test/test_enumerate.cpp +++ b/test/test_enumerate.cpp @@ -137,6 +137,15 @@ TEST_CASE("enumerate: iterator meets requirements", "[enumerate]") { REQUIRE(itertest::IsIterator::value); } +TEST_CASE("enumerate: works with pipe", "[enumerate]") { + constexpr char str[] = {'a', 'b', 'c'}; + auto e = str | enumerate; + Vec v(std::begin(e), std::end(e)); + Vec vc{{0, 'a'}, {1, 'b'}, {2, 'c'}}; + + REQUIRE(v == vc); +} + template using ImpT = decltype(enumerate(std::declval())); TEST_CASE("enumerate: has correct ctor and assign ops", "[enumerate]") { From a4e454f9229955c640585aa8f4117fc6a6c5cefa Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 3 Apr 2016 18:59:06 -0700 Subject: [PATCH 1371/1866] formatting --- test/test_chain.cpp | 10 ++-- test/test_imap.cpp | 8 +-- test/test_sorted.cpp | 6 +- test/test_starmap.cpp | 132 +++++++++++++++++++++--------------------- 4 files changed, 77 insertions(+), 79 deletions(-) diff --git a/test/test_chain.cpp b/test/test_chain.cpp index 8594e73a..7630270b 100644 --- a/test/test_chain.cpp +++ b/test/test_chain.cpp @@ -194,11 +194,11 @@ 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: 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", diff --git a/test/test_imap.cpp b/test/test_imap.cpp index 9a19cd87..f150d3aa 100644 --- a/test/test_imap.cpp +++ b/test/test_imap.cpp @@ -42,10 +42,10 @@ TEST_CASE("imap: works with lambda, callable, and function", "[imap]") { } SECTION("with callable") { - auto im = imap(PlusOner{}, ns); - Vec v(std::begin(im), std::end(im)); - Vec vc = {11, 21, 31}; - REQUIRE( v == vc ); + auto im = imap(PlusOner{}, ns); + Vec v(std::begin(im), std::end(im)); + Vec vc = {11, 21, 31}; + REQUIRE(v == vc); } SECTION("with function") { diff --git a/test/test_sorted.cpp b/test/test_sorted.cpp index cc477f84..f6c902ba 100644 --- a/test/test_sorted.cpp +++ b/test/test_sorted.cpp @@ -181,7 +181,7 @@ TEST_CASE("sorted: has correct ctor and assign ops", "[sorted]") { } TEST_CASE("sorted: iterator meets requirements", "[sorted]") { - Vec v; - auto r = sorted(v); - REQUIRE( itertest::IsIterator::value ); + Vec v; + auto r = sorted(v); + REQUIRE(itertest::IsIterator::value); } diff --git a/test/test_starmap.cpp b/test/test_starmap.cpp index 994f96b7..751d3d4e 100644 --- a/test/test_starmap.cpp +++ b/test/test_starmap.cpp @@ -12,100 +12,98 @@ using iter::starmap; namespace { - long f(long d, int i) { - return d * i; + long f(long d, int i) { + return d * i; + } + + std::string g(const std::string& s, int i, char c) { + std::stringstream ss; + ss << s << ' ' << i << ' ' << c; + return ss.str(); + } + + struct Callable { + int operator()(int a, int b, int c) { + return a + b + c; } - std::string g(const std::string& s, int i, char c) { - std::stringstream ss; - ss << s << ' ' << i << ' ' << c; - return ss.str(); + int operator()(int a) { + return a; } - - 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]") { - 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 ); - } + using Vec = const std::vector; + const std::vector> v1 = {{1l, 2}, {3l, 11}, {6l, 7}}; + Vec vc = {2l, 33l, 42l}; - 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 ); - } + 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); + } } 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'}}; + 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"}; + 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 ); + 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}; + 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 ); + 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); + 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}; + Vec v(std::begin(sm), std::end(sm)); + Vec vc = {2115, 16}; - REQUIRE( v == vc ); + 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() ); + itertest::BasicIterable> bi{}; + starmap(Callable{}, bi); + REQUIRE_FALSE(bi.was_moved_from()); + 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 ); + std::string s{}; + const std::vector> v1; + 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 ); +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 060632ec27056960b0866f533514efaf40fcf521 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 3 Apr 2016 18:59:23 -0700 Subject: [PATCH 1372/1866] Make general use currier for passing first arg --- internal/iterbase.hpp | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index afa9d0fd..c109c477 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -50,12 +50,12 @@ namespace iter { using iterator_traits_deref = std::remove_reference_t>; - template + template struct IsIterable : std::false_type {}; // Assuming that if a type works with std::begin, it is an iterable. template - struct IsIterable>> : std::true_type{}; + struct IsIterable>> : std::true_type {}; template constexpr bool is_iterable = IsIterable::value; @@ -209,7 +209,6 @@ namespace iter { using iterator_tuple_type = decltype(detail::iterator_tuple_type_helper(std::declval())); - // Given a tuple template argument, evaluates to a tuple of // what the iterators for the template argument's contained types // dereference to @@ -230,7 +229,7 @@ namespace iter { decltype(auto) call_with_tuple_impl( Func&& mf, TupleType&& tup, std::index_sequence) { return mf(std::forward>>(std::get(tup))...); + std::remove_reference_t>>(std::get(tup))...); } } @@ -329,14 +328,33 @@ namespace iter { // allows f(x) to be 'called' as x | f // let the record show I dislike adding yet another syntactical mess to // this clown car of a language. - template + template struct Pipeable { - template - friend decltype(auto) operator|(T&& x, const Pipeable& p) { - return static_cast(p)(std::forward(x)); + template + friend decltype(auto) operator|(T&& x, const Pipeable& p) { + return static_cast(p)(std::forward(x)); + } + }; + + // T is whatever is being held for later use + template + struct FnPartial : Pipeable> { + ItTool tool_fun; + mutable T t; + FnPartial(ItTool in_tool, T in_t) + : tool_fun(std::move(in_tool)), t(std::move(in_t)) {} + template + auto operator()(Container&& container) const { + return tool_fun(t, std::forward(container)); } }; +#if 0 + template + struct PipeableAndBindFirst : Pipeable { + + }; +#endif } } From d5b68aa5a76818bf007f100beace81602dc375b9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 3 Apr 2016 19:00:04 -0700 Subject: [PATCH 1373/1866] formatting --- test/test_filter.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/test_filter.cpp b/test/test_filter.cpp index cc68f616..63b8e068 100644 --- a/test/test_filter.cpp +++ b/test/test_filter.cpp @@ -73,12 +73,12 @@ TEST_CASE("filter: using identity", "[filter]") { TEST_CASE("filter: skips null pointers", "[filter]") { int a = 1; int b = 2; - const std::vector ns = {0, &a, nullptr, nullptr, &b, nullptr}; + const std::vector ns = {0, &a, nullptr, nullptr, &b, nullptr}; auto f = filter(ns); - const std::vector v(std::begin(f), std::end(f)); - const std::vector vc = {&a, &b}; - REQUIRE( v == vc ); + const std::vector v(std::begin(f), std::end(f)); + const std::vector vc = {&a, &b}; + REQUIRE(v == vc); } TEST_CASE("filter: binds to lvalues, moves rvales", "[filter]") { @@ -145,7 +145,6 @@ TEST_CASE("filter: using identity and pipe", "[filter]") { REQUIRE(v == vc); } - TEST_CASE("filter: iterator meets requirements", "[filter]") { std::string s{}; auto c = filter([] { return true; }, s); From 1c1843e247119ffcc8a09436fa0257dc7a0cd45f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 3 Apr 2016 19:00:09 -0700 Subject: [PATCH 1374/1866] uses general FnPartial --- filter.hpp | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/filter.hpp b/filter.hpp index 6ea9c0f8..31da8842 100644 --- a/filter.hpp +++ b/filter.hpp @@ -132,20 +132,10 @@ class iter::impl::FilterFn : public iter::impl::Pipeable { return (*this)(BoolTester>{}, std::move(il)); } - template - struct FilterFnPartial : Pipeable> { - FilterFnPartial(FilterFunc f) : fun(std::move(f)) {} - template - auto operator()(Container&& container) const { - return FilterFn{}(fun, std::forward(container)); - } - private: - FilterFunc fun; - }; - - template >> - FilterFnPartial operator()(FilterFunc filter_func) const { - return {filter_func}; + template >> + FnPartial operator()(FilterFunc filter_func) const { + return {*this, std::move(filter_func)}; } private: From 632d45131ac78b62357eb05cc0d996626de9e25b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 3 Apr 2016 19:55:47 -0700 Subject: [PATCH 1375/1866] minor FnPartial improvements --- internal/iterbase.hpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index c109c477..64eae3e4 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -340,21 +340,23 @@ namespace iter { template struct FnPartial : Pipeable> { ItTool tool_fun; - mutable T t; - FnPartial(ItTool in_tool, T in_t) - : tool_fun(std::move(in_tool)), t(std::move(in_t)) {} + mutable T stored_arg; + constexpr FnPartial(ItTool in_tool, T in_t) + : tool_fun(in_tool), stored_arg(in_t) {} + template auto operator()(Container&& container) const { - return tool_fun(t, std::forward(container)); + return tool_fun(stored_arg, std::forward(container)); } }; -#if 0 template struct PipeableAndBindFirst : Pipeable { - + template >> + FnPartial operator()(Func func) const { + return {static_cast(*this), std::move(func)}; + } }; -#endif } } From e83e6a68e2b0c22ab03f8de6e1a7763720662691 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 3 Apr 2016 19:56:08 -0700 Subject: [PATCH 1376/1866] uses base class partial overload --- filter.hpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/filter.hpp b/filter.hpp index 31da8842..79e8d810 100644 --- a/filter.hpp +++ b/filter.hpp @@ -107,7 +107,7 @@ class iter::impl::Filtered { } }; -class iter::impl::FilterFn : public iter::impl::Pipeable { +class iter::impl::FilterFn : public PipeableAndBindFirst { public: template iter::impl::Filtered operator()( @@ -131,12 +131,7 @@ class iter::impl::FilterFn : public iter::impl::Pipeable { auto operator()(std::initializer_list il) const { return (*this)(BoolTester>{}, std::move(il)); } - - template >> - FnPartial operator()(FilterFunc filter_func) const { - return {*this, std::move(filter_func)}; - } + using PipeableAndBindFirst::operator(); private: template From c708b40579b49bdf05b1c3921af79463e1f3d442 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 4 Apr 2016 22:36:07 -0700 Subject: [PATCH 1377/1866] Removes extra "class" in friend declarations. --- chain.hpp | 4 ++-- enumerate.hpp | 2 +- filter.hpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/chain.hpp b/chain.hpp index 66fd0f91..470ca4e3 100644 --- a/chain.hpp +++ b/chain.hpp @@ -28,7 +28,7 @@ namespace iter { template class iter::impl::Chained { private: - friend class ChainMaker; + friend ChainMaker; static_assert(std::tuple_size>::value == sizeof...(Is), "tuple size != sizeof Is"); @@ -171,7 +171,7 @@ template class iter::impl::ChainedFromIterable { private: Container container; - friend class ChainMaker; + friend ChainMaker; ChainedFromIterable(Container&& in_container) : container(std::forward(in_container)) {} diff --git a/enumerate.hpp b/enumerate.hpp index 1c4fb666..f85c8e21 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -23,7 +23,7 @@ class iter::impl::Enumerable { Container container; const std::size_t start; - friend struct EnumerateFn; + friend EnumerateFn; // for IterYield using BasePair = std::pair>; diff --git a/filter.hpp b/filter.hpp index 79e8d810..b2da5994 100644 --- a/filter.hpp +++ b/filter.hpp @@ -22,7 +22,7 @@ class iter::impl::Filtered { Container container; FilterFunc filter_func; - friend class FilterFn; + friend FilterFn; // Value constructor for use only in the filter function Filtered(FilterFunc in_filter_func, Container&& in_container) From efe0c77b24988ad76eb1c359bb32ff478b731538 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 7 Apr 2016 00:30:23 -0700 Subject: [PATCH 1378/1866] adds explicit "u" to enumerate start val --- test/test_enumerate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_enumerate.cpp b/test/test_enumerate.cpp index 38b3a90a..5d0e67e6 100644 --- a/test/test_enumerate.cpp +++ b/test/test_enumerate.cpp @@ -50,7 +50,7 @@ TEST_CASE("Postfix ++ enumerate", "[enumerate]") { TEST_CASE("enumerate: with starting value", "[enumerate]") { std::string str = "hey"; - auto e = enumerate(str, 5); + auto e = enumerate(str, 5u); Vec v(std::begin(e), std::end(e)); Vec vc{{5, 'h'}, {6, 'e'}, {7, 'y'}}; From 3a8f11d6f1103b4a2bf4dca6f650a18bc7124f6e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 7 Apr 2016 00:34:35 -0700 Subject: [PATCH 1379/1866] Adds IterToolFn to generalize the callables --- internal/iterbase.hpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index 64eae3e4..7d8acb0d 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -357,6 +357,22 @@ namespace iter { return {static_cast(*this), std::move(func)}; } }; + + // Pipeable Callable generator, where ItImpl is templated on the first + // argument to the call. + template