Code Monkey home page Code Monkey logo

cppitertools's Introduction

CPPItertools

Range-based for loop add-ons inspired by the Python builtins and itertools library. Like itertools and the Python3 builtins, this library uses lazy evaluation wherever possible.

Note: Everything is inside the iter namespace.

Follow @cppitertools for updates.

Build and Test Status

Status Compilers
Travis Build Status gcc-7 gcc-8 gcc-9 clang-5.0 clang-6.0 clang-7 clang-8 clang-9
Appveyor Build Status MSVC 2017 MSVC 2019

Table of Contents

range
enumerate
zip
zip_longest
imap
filter
filterfalse
unique_everseen
unique_justseen
takewhile
dropwhile
cycle
repeat
count
groupby
starmap
accumulate
compress
sorted
chain
chain.from_iterable
reversed
slice
sliding_window
chunked
batched

Combinatoric fuctions

product
combinations
combinations_with_replacement
permutations
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 <cppitertools/itertools.hpp> 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 <cppitertools/enumerate.hpp> for example).

Running tests

You may use either scons or bazel to build the tests. scons seems to work better with viewing the test output, but the same bazel command can be run from any directory.

To run tests with scons you must be within the test directory

test$ # build and run all tests
test$ scons
test$ ./test_all
test$ # build and run a specific test
test$ scons test_enumerate
test$ ./test_enumerate
test$ valgrind ./test_enumerate

bazel absolute commands can be run from any directory inside the project

$ bazel test //test:all # runs all tests
$ bazel test //test:test_enumerate # runs a specific test

Requirements of passed objects

Most itertools will work with iterables using InputIterators and not copy or move any underlying elements. The itertools that need ForwardIterators or 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.

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 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

std::vector<int> 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:

for (auto&& p : enumerate(std::vector<int>{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<int> 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.

Pipe syntax

Wherever it makes sense, I've implemented the "pipe" operator that has become common in similar libraries. When the syntax is available, it is done by pulling out the iterable from the call and placing it before the tool. For example:

filter(pred, seq);  // regular call
seq | filter(pred);  // pipe-style
enumerate(seq);  // regular call
seq | enumerate;  // pipe-style.

The following tools support pipe. The remaining I left out because although some of them have multiple reasonable versions, it wasn't obvious to me how I would expect them to behave:

  • accumulate
  • chain.from_iterable
  • chunked
  • batched
  • combinations
  • combinations_with_replacement
  • cycle
  • dropwhile
  • enumerate
  • filter
  • filterfalse
  • groupby
  • imap
  • permutations
  • powerset
  • reversed
  • slice
  • sliding_window
  • sorted
  • starmap
  • takewhile
  • unique_everseen (*only without custom hash and equality callables)
  • unique_justseen

I don't personally care for the piping style, but it seemed to be desired by the users.

range

Uses an underlying iterator to achieve the same effect of the python range function. range can be used in three different ways:

Only the stopping point is provided. Prints 0 1 2 3 4 5 6 7 8 9

for (auto i : range(10)) {
    cout << i << '\n';
}

The start and stop are both provided. Prints 10 11 12 13 14

for (auto i : range(10, 15)) {
    cout << i << '\n';
}

The start, stop, and step are all provided. Prints 20 22 24 26 28

for (auto i : range(20, 30, 2)) {
    cout << i << '\n';
}

Negative values are allowed as well. Prints 2 1 0 -1 -2

for (auto i : range(2, -3, -1)) {
    cout << i << '\n';
}

A step size of 0 results in an empty range (Python's raises an exception). The following prints nothing

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

Prints: 5.0 5.5 6.0 ... 9.5

for(auto i : range(5.0, 10.0, 0.5)) {
    cout << i << '\n';
}

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.

range also supports the following operations:

  • .size() to get the number of elements in the range (not enabled for floating point ranges).
  • Accessors for .start(), .stop(), and .step().
  • Indexing. Given a range r, r[n] is the nth element in the range.

enumerate

Continually "yields" containers similar to pairs. They are structs with the index in .first, and the element in .second, and also work with structured binding declarations. Usage appears as:

vector<int> vec{2, 4, 6, 8};
for (auto&& [i, e] : enumerate(vec)) {
    cout << i << ": " << e << '\n';
}

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

vector<int> 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.

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

vector<int> vec{1, 5, 4, 0, 6, 7, 3, 0, 2, 8, 3, 2, 1};
for (auto&& i : filterfalse([] (int i) { return i > 4; }, vec)) {
    cout << i <<'\n';
}

If no predicate is passed, the elements themselves are tested for truth.

Prints only zero values.

for(auto&& i : filterfalse(vec)) {
    cout << i << '\n';
}

unique_everseen

Additional Requirements: Underlying values must be copy-constructible.

This is a filter adaptor that only generates values that have never been seen before.

Prints 1 2 3 4 5 6 7 8 9

vector<int> 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_everseen uses an undordered_set so it needs hashable elements. For types that don't work with std::hash or std::equal_to, unique_everseen also provides an overload taking a hash callable and an equality callable. This does not work with the pipe syntax.

vector<Widget> v { /* ... */ };
for (auto&& w : unique_everseen(v, WidgetHash{}, WidgetEq{})) {
  cout << w.name() << ' ';
}

unique_justseen

Another filter adaptor that only omits consecutive duplicates.

Prints 1 2 3 4 3 2 1 Example Usage:

vector<int> v {1,1,1,2,2,3,3,3,4,3,2,1,1,1};
for (auto&& i : unique_justseen(v)) {
    cout << i << ' ';
}

If elements cannot be directly compared with equality, you can pass in a key callable.

vector<Person> v { /* ... */ };
for (auto&& p : unique_justseen(v, [] (const Person& p) { return p.name; }))
  cout << p.name() << ' ' << p.age() << '\n';
}

takewhile

Yields elements from an iterable until the first element that is false under the predicate is encountered.

Prints 1 2 3 4. (5 is false under the predicate)

vector<int> ivec{1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1};
for (auto&& i : takewhile([] (int i) {return i < 5;}, ivec)) {
    cout << i << '\n';
}

dropwhile

Yields all elements after and including the first element that is true under the predicate.

Prints 5 6 7 1 2

vector<int> ivec{1, 2, 3, 4, 5, 6, 7, 1, 2};
for (auto&& i : dropwhile([] (int i) {return i < 5;}, ivec)) {
    cout << i << '\n';
}

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.

Prints 1 2 3 repeatedly until some_condition is true

vector<int> vec{1, 2, 3};
for (auto&& i : cycle(vec)) {
    cout << i << '\n';
    if (some_condition) {
        break;
    }
}

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.

for (auto&& e : repeat(1, 5)) {
    cout << e << '\n';
}

The below prints 2 forever

for (auto&& e : repeat(2)) {
    cout << e << '\n';
}

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() would eventually exceed the maximum possible value for its type (or minimum with a negative step). count is actually implemented as a range with the stopping point being the std::numeric_limits<T>::max() for the integral type (long by default)

The below will print 0 1 2 ... etc

for (auto&& i : count()) {
    cout << i << '\n';
}

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.

vector<string> 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, if the group is unsorted, the same key may appear multiple times.

starmap

Takes a sequence of tuple-like objects (anything that works with std::get) and unpacks each object into individual arguments for each function call. The below example takes a vector of pairs of ints, and passes them to a function expecting two ints, with the elements of the pair being the first and second arguments to the function.

vector<pair<int, int>> 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

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

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

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. Prints: 1 3 6 10 15

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

for (auto&& i : accumulate(range(1, 6), std::multiplies<int>{})) {
    cout << i << '\n';
}

Note: The intermediate result type must support default construction 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 the elements the iterators were holding.

Example usage:

array<int,4> iseq{{1,2,3,4}};
vector<float> fseq{1.2,1.4,12.3,4.5,9.9};
vector<string> sseq{"i","like","apples","a lot","dude"};
array<double,5> dseq{{1.2,1.2,1.2,1.2,1.2}};

for (auto&& [i, f, s, d] : zip(iseq, fseq, sseq, dseq)) {
    cout << i << ' ' << f << ' ' << s << ' ' << d << '\n';
    f = 2.2f; // modifies the underlying 'fseq' sequence
}

zip_longest

Terminates on the longest sequence instead of the shortest. Repeatedly yields a tuple of boost::optional<T>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.

vector<int> v1 = {0, 1, 2, 3};
vector<int> v2 = {10, 11};
for (auto&& [x, y] : zip_longest(v1, v2)) {
    cout << '{';
    if (x) {
        cout << "Just " << *x;
    } else {
        cout << "Nothing";
    }
    cout << ", ";
    if (y) {
        cout << "Just " << *y;
    } else {
        cout << "Nothing";
    }
    cout << "}\n";
}

The output is:

{Just 0, Just 10}
{Just 1, Just 11}
{Just 2, Nothing}
{Just 3, Nothing}

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

vector<int> 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

vector<int> vec1{1, 3, 5, 7, 9, 11};
vector<int> 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

Yields only the values corresponding to true in the selectors iterable. Terminates on the shortest sequence.

Prints 2 6

vector<int> ivec{1, 2, 3, 4, 5, 6};
vector<bool> bvec{false, true, false, false, false, true};
for (auto&& i : compress(ivec, bvec) {
    cout << i << '\n';
}

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. sorted also takes an optional second comparator 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.

unordered_set<int> nums{4, 0, 2, 1, 3};
for (auto&& i : sorted(nums)) {
    cout << i << '\n';
}

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.

vector<int> empty{};
vector<int> vec1{1,2,3,4,5,6};
array<int,4> arr1{{7,8,9,10}};

for (auto&& i : chain(empty,vec1,arr1)) {
    cout << i << '\n';
}

chain.from_iterable

Similar to chain, but rather than taking a variadic number of iterables, it takes an iterable of iterables and chains the contained iterables together. A simple example is shown below using a vector of vectors to represent a 2d ragged array, and prints it in row-major order.

vector<vector<int>> matrix = {
    {1, 2, 3},
    {4, 5},
    {6, 8, 9, 10, 11, 12}
};

for (auto&& i : chain.from_iterable(matrix)) {
    cout << i << '\n';
}

reversed

Additional Requirements: Input must be compatible with std::rbegin() and std::rend()

Iterates over elements of a sequence in reverse order.

for (auto&& i : reversed(a)) {
    cout << i << '\n';
}

slice

Returns selected elements from a range, parameters are start, stop and step. the range returned is [start,stop) where you only take every step element

This outputs 0 3 6 9 12

vector<int> a{0,1,2,3,4,5,6,7,8,9,10,11,12,13};
for (auto&& i : slice(a,0,15,3)) {
    cout << i << '\n';
}

sliding_window

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]

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:

vector<int> 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';
}

chunked

chunked will yield subsequent chunks of an iterable in blocks of a specified size. The final chunk may be shorter than the rest if the chunk size given does not evenly divide the length of the iterable.

Example usage:

vector<int> v {1,2,3,4,5,6,7,8,9};
for (auto&& sec : chunked(v,4)) {
    for (auto&& i : sec) {
        cout << i << ' ';
    }
    cout << '\n';
}

The above prints:

1 2 3 4
5 6 7 8
9

batched

batched will yield a given number N of batches containing subsequent elements from an iterable, assuming the iterable contains at least N elements. The size of each batch is immaterial, but the implementation guarantees that no two batches will differ in size by more than 1.

Example usage:

vector<int> v {1,2,3,4,5,6,7,8,9};
for (auto&& sec : batched(v,4)) {
    for (auto&& i : sec) {
        cout << i << ' ';
    }
    cout << '\n';
}

The above prints:

1 2 3
4 5
6 7
8 9

product

Additional Requirements: Input must have a ForwardIterator

Generates the cartesian product of the given ranges put together.

Example usage:

vector<int> v1{1,2,3};
vector<int> v2{7,8};
vector<string> v3{"the","cat"};
vector<string> v4{"hi","what's","up","dude"};
for (auto&& [a, b, c, d] : product(v1,v2,v3,v4)) {
    cout << a << ", " << b << ", " << c << ", " << d << '\n';
}

Product also accepts a "repeat" as a template argument. Currently this is the only way to do repeats. If you are reading this and need product(seq, 3) instead of product<3>(seq) please open an issue.

Example usage:

std::string s = "abc";
// equivalent of product(s, s, s);
for (auto&& t : product<3>(s)) {
   // ...
}

combinations

Additional Requirements: Input must have a ForwardIterator

Generates n length unique sequences of the input range.

Example usage:

vector<int> v = {1,2,3,4,5};
for (auto&& i : combinations(v,3)) {
    for (auto&& j : i ) cout << j << " ";
    cout << '\n';
}

combinations_with_replacement

Additional Requirements: Input must have a ForwardIterator

Like combinations, but with replacement of each element. The below is printed by the loop that follows:

{A, A}
{A, B}
{A, C}
{B, B}
{B, C}
{C, C}
for (auto&& v : combinations_with_replacement(s, 2)) {
    cout << '{' << v[0] << ", " << v[1] << "}\n";
}

permutations

Additional Requirements: Input must have a ForwardIterator. Iterator must have an operator*() const.

Generates all the permutations of a range using std::next_permutation.

Example usage:

vector<int> v = {1,2,3,4,5};
for (auto&& vec : permutations(v)) {
    for (auto&& i : vec) {
        cout << i << ' ';
    }
    cout << '\n';
}

powerset

Additional Requirements: Input must have a ForwardIterator

Generates every possible subset of a set, runs in O(2^n).

Example usage:

vector<int> vec {1,2,3,4,5,6,7,8,9};
for (auto&& v : powerset(vec)) {
    for (auto&& i : v) {
        cout << i << " ";
    }
    cout << '\n';
}

cppitertools's People

Contributors

aaronjosephs avatar anirul avatar benjones avatar dmckeone avatar frboyer avatar grimreaper avatar jared-schmitz avatar jkhoogland avatar kc9jud avatar maxmarsc avatar mbradac avatar mbrukman avatar nvander1 avatar pnacht avatar reach2sayan avatar ryanhaining avatar ssbotelh avatar strega-nil avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cppitertools's Issues

[c++17] enumerate should work with structured bindings

Currently this is invalid with c++17

for (auto&& [i, e] : iter::enumerate(seq)) {
    // ...
}

because the object returned by enumerate's iterator's operator* is a subclass of pair with more data members. In some way, the above should work.

inconsistent type deduction behavior with old imap and new(starmap) imap implementation

In the older version of imap, which was not implemented on top of starmap, you could say something like

auto fn = []{};
using MapType = decltype(iter::imap(fn, 1));

MapType isn't terribly useful here, you couldn't actually iterate through it, but the behavior is consistent with most other itertools. In the new version, the above code fails to compile.

Default include

Hi.

Gr8 library.

It would be very helpful if all includes used "" instead of <>. That way, there is no need to add the entire cppitertools directory to the include path, e.g. It would be better to just drop the entire library in the regular include path and just do

include <cppitertools/itertools.hpp>

and everything will work.

Make available via conan

Conan is besides Microsoft's vcpkg the most popular package manager for C++ out there. But with good support for cmake and linux in contrast to vcpkg.
We use them it in our C++ projects to pull in dependencies without including them into our source code or installing them on the building system. See for example https://bintray.com/stiffstream/public/restinio%3Astiffstream for how libraries are published on conan.

Would you consider to publish cppitertools on conan? We could help with conanizing cppitertools.

FYI @Shaheen47

Combining reversed with zip (and possibly others)

I tried to use reversed in conjunction with zip in a ranged-based for loop, i.e.

for (auto&& tup : reversed(zip(container1, container2))) { ... }

Unfortunately, this results in error messages stating that there is no rbegin() function. Indeed, I didn't find that function in zip.hpp. Are there any plans to add this functionality, possibly also to the other range expressions?

`iter::product` of `iter::range`'s

Hi,

I was trying to compose iter::product with iter::range so as to iterate over all the coordinate pairs of a matrix. Unfortunately, I can't manage to get it work with iter::range, wheres there's no problem with ranges generated with boost::irange. Here's a showcase example:

int main() {

    // this work
    for (auto&& ij: iter::product(boost::irange(0, 10), boost::irange(0, 5))) {
        std::cout << std::get<0>(ij) << "," << std::get<1>(ij) << std::endl;
    }

    // this does not work
    for (auto&& ij: iter::product(iter::range(10), iter::range(5))) {
        std::cout << std::get<0>(ij) << "," << std::get<1>(ij) << std::endl;
    }   
}

clang reports:

note: copy assignment operator of 'Iterator' is implicitly deleted because field 'step' is of const-qualified type 'const int'
                    const T step;

Thanks and sorry for submitting two reports in a row!

vector<bool> and groupby

Hi

I'm getting another strange behaviour:

  vector<bool> v{true, true, false, false,false, true, true};
  for (auto &&x: iter::groupby(v,[](auto b){return b;})) {
    cout << "group: ";
    for (auto &&g: x.second)
      cout << g << " ";
    cout << endl;
  }

prints

group: 1 1 0 0 0 1 1 

yet

  vector<int> v{5,5,5,3,3};
  for (auto &&x: iter::groupby(v,[](auto b){return b;})) {
    cout << "group: ";
    for (auto &&g: x.second)
      cout << g << " ";
    cout << endl;
  }

prints

group: 5 5 5 
group: 3 3

Is there a reason why it shouldn't work with bool ?

Can I get just the counts from combinations_with_replacement ?

I am interested in using this library to iterate over all "n multichoose k" possibilities for a multiset, but I am representing each set as a simple vector of counts, with length n, where all counts add up to k. Is it possible to extract the counts from your iterators without iterating through each "multiset" itself? I had a peek at the headers but I am a bit lost as to how its working exactly.

So using the provided example for combinations_with_replacement, I would like to get a simple result that would look like:

combinations_with_replacement({1, 2}, 4):
{ 4 0 }
{ 3 1 }
{ 2 2 }
{ 1 3 }
{ 0 4 }

Using SFINAE to detect for certain methods

For example slice currently needs a random access iterator. We should detect if one exists for the iterable if it doesn't a different method of using slice should be used

Drop support for deduced std::initializer_list

Maintaining everything with duplicate functions that can deduce std::initializer_list feels like more trouble than it's worth. I doubt anyone makes use of it (I don't), especially because none of the variadic functions can support it and I haven't heard any complaints.

Will be likely be removed alongside the | operator updates (unless anyone out there says they've used these functions for real).

Feature request: Something like list comprehension

First, I love this library. As soon as I first read of range-based for loops, I wanted this. Now, the feature request...

It would be great to have a way to transform all of the elements in an iterator, as is often done with list comprehensions in python.

for (auto&& p : transform([](int x) { return x*x; }, range(10))) { /* ... */ }

or

for (auto&& p : range(10) | transform([](int x) { return x*x; })) { /* ... */ }

If there is some magic in C++ to do this already, perhaps that can go as an example in the readme.

Boost unit tests

We have a whole testing directory right now and the tests are fine. But I want to adapt them to use the boost unit test framework, this will make the tests more useful by actually checking something instead of just running and exiting

Support for std::begin & std::end

I have noted that your the container class must have a .begin() method otherwise you cannot declare the iterators. However, if you use declvar any iterable that support std::begin() (like static arrays) will also work in your framework. For instance, here's how I would declare a typedef for iterator_type:

typedef decltype(std::begin(std::declval<Iterable&>())) iterator_type;

Now the iterable can be:

  • vector
  • static array
  • map
    ..

cannot iterate over const chain object.

The following fails, can't construct the iterator

#include <vector>

#include "cppitertools/chain.hpp"

int main() {
  std::vector<char> v1 = {'a'};
  std::vector<char> v2 = {'b'};
  const auto ch = iter::chain(v1, v2);
  std::begin(ch);
}

Because the chain begin() const is saying that the iterator needs a const tuple<Ts...> while what it actually gets is tuple<const Ts...>

Support for move only types

Hi,

I would like to use the library with move only types. Here's a toy example:

#include <iostream>
#include <vector>
#include <itertools/product.hpp>

struct MoveOnlyType {
    MoveOnlyType() = default;
    MoveOnlyType(MoveOnlyType const& other) = delete;
    MoveOnlyType(MoveOnlyType&& other) = default;
    MoveOnlyType& operator=(MoveOnlyType const& other) = delete;
    MoveOnlyType& operator=(MoveOnlyType&& other) = default;
};

int main() {

    std::vector<MoveOnlyType> v1, v2;
    v1.push_back(MoveOnlyType());
    v1.push_back(MoveOnlyType());

    v2.push_back(MoveOnlyType());
    v2.push_back(MoveOnlyType());
    v2.push_back(MoveOnlyType());


    for (auto&& pair_of_moveonly: iter::product(v1, v2)) 
        std::cout << "it does not work" << std::endl;
}

Thanks.

`error: 'rbegin' is not a member of 'std'` - C++11 compliancy

I am experiencing problems compiling with gcc-4.9.3. On trying to compile a simple zip, I get the following error message:

cppitertools/reversed.hpp:29:16: error: 'rbegin' is not a member of 'std'

It seems to me that this issue is due to cppitertools using C++14 features and my standard library not being C++14 compliant, as is explained here.
Should the library still work in a C++11 environment or is there some other problem on my behalf?

Edit:
I now tested with gcc-5.3 and -std=c++11, which gives similar errors. Activating -std=c++14 fixes the problem.
The issue boils down to:

Implementation of python itertools and builtin iteration functions for C++14

Combining enumerate with filter

Hello,
as fist step, thanks for this great library!

Now with the issue:

std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8};

auto f = iter::enumerate(v) | iter::filter([](auto& i) { return std::get<1>(i) > 4; });

for (auto&& [i, e]: f) {
    std::cout << i << ", " << e << '\n';
}

This snippet doesn't compile (g++ 7.4), with error:

error: use of deleted function ‘std::optional<iter::impl::EnumIterYield<long unsigned int, int&> >& std::optional<iter::impl::EnumIterYield<long unsigned int, int&> >::operator=(std::optional<iter::impl::EnumIterYield<long unsigned int, int&> >&&)’

I opened StackOverflow question, since I'm not sure if I didn't do something wrong - https://stackoverflow.com/questions/57648457/cppitertools-how-to-combine-iterenumerate-and-iterfilter

Is it possible to combine filter with enumerate this way? The solutions appears is to change iterbase.hpp:301 from item_p_ = std::move(item); to item_p_.emplace(std::move(item));

groupby segmentation fault

Hi

I'm getting a segmentation fault with the following code:

  std::vector<int> v{true,true,true,false,false,true,true};
  auto a = iter::groupby(v,[](bool b){return b;});
  auto b = iter::filter([](auto &g){ return g.first;},a);
  auto c = iter::imap([](auto &g){ return std::distance(g.second.begin(), g.second.end()); }, b);
  for (size_t x: c)
    std::cout << x;

I'm trying to get the size of the longest sequence of trues.

Program received signal SIGSEGV, Segmentation fault.
0x00005555556117b1 in __gnu_cxx::operator!=<int*, std::vector<int, std::allocator<int> > > (__lhs=<error reading variable: Cannot access memory at address 0x0>, __rhs=<error reading variable: Cannot access memory at address 0x8>) at /usr/include/c++/8/bits/stl_iterator.h:887
887	    { return __lhs.base() != __rhs.base(); }

#0  0x00005555556117b1 in __gnu_cxx::operator!=<int*, std::vector<int, std::allocator<int> > > (__lhs=<error reading variable: Cannot access memory at address 0x0>, __rhs=<error reading variable: Cannot access memory at address 0x8>) at /usr/include/c++/8/bits/stl_iterator.h:887
#1  0x00005555555e99e2 in iter::impl::GroupProducer<std::vector<int, std::allocator<int> >&, main(int, char**)::<lambda(bool)> >::Iterator<std::vector<int, std::allocator<int> >&>::increment_iterator(void) (this=0x0) at /home/miguel/Development/IPL/investigacao/vad_check/cppitertools/groupby.hpp:148
#2  0x00005555555e951b in iter::impl::GroupProducer<std::vector<int, std::allocator<int> >&, main(int, char**)::<lambda(bool)> >::Group<std::vector<int, std::allocator<int> >&>::GroupIterator::operator++(void) (this=0x7fffffffc520) at /home/miguel/Development/IPL/investigacao/vad_check/cppitertools/groupby.hpp:247
#3  0x00005555555e9088 in std::__distance<iter::impl::GroupProducer<std::vector<int>&, main(int, char**)::<lambda(bool)> >::Group<std::vector<int>&>::GroupIterator>(iter::impl::GroupProducer<std::vector<int, std::allocator<int> >&, main(int, char**)::<lambda(bool)> >::Group<std::vector<int, std::allocator<int> >&>::GroupIterator, iter::impl::GroupProducer<std::vector<int, std::allocator<int> >&, main(int, char**)::<lambda(bool)> >::Group<std::vector<int, std::allocator<int> >&>::GroupIterator, std::input_iterator_tag) (__first=..., __last=...) at /usr/include/c++/8/bits/stl_iterator_base_funcs.h:89
#4  0x00005555555e8843 in std::distance<iter::impl::GroupProducer<std::vector<int>&, main(int, char**)::<lambda(bool)> >::Group<std::vector<int>&>::GroupIterator>(iter::impl::GroupProducer<std::vector<int, std::allocator<int> >&, main(int, char**)::<lambda(bool)> >::Group<std::vector<int, std::allocator<int> >&>::GroupIterator, iter::impl::GroupProducer<std::vector<int, std::allocator<int> >&, main(int, char**)::<lambda(bool)> >::Group<std::vector<int, std::allocator<int> >&>::GroupIterator) (__first=..., __last=...) at /usr/include/c++/8/bits/stl_iterator_base_funcs.h:141
#5  0x00005555555e6d10 in <lambda(auto:5&)>::operator()<std::pair<bool, iter::impl::GroupProducer<std::vector<int>&, main(int, char**)::<lambda(bool)> >::Group<std::vector<int>&> > >(std::pair<bool, iter::impl::GroupProducer<std::vector<int>&, main(int, char**)::<lambda(bool)> >::Group<std::vector<int, std::allocator<int> >&> > &) const (__closure=0x7fffffffc870, g={...}) at /home/miguel/Development/IPL/investigacao/vad_check/src/main.cc:456
#6  0x00005555555e90cc in std::__invoke_impl<long int, main(int, char**)::<lambda(auto:5&)>&, std::pair<bool, iter::impl::GroupProducer<std::vector<int>&, main(int, char**)::<lambda(bool)> >::Group<std::vector<int, std::allocator<int> >&> >&>(std::__invoke_other, <lambda(auto:5&)> &, std::pair<bool, iter::impl::GroupProducer<std::vector<int>&, main(int, char**)::<lambda(bool)> >::Group<std::vector<int, std::allocator<int> >&> > &) (__f=..., __args#0={...}) at /usr/include/c++/8/bits/invoke.h:60
#7  0x00005555555e887c in std::__invoke<main(int, char**)::<lambda(auto:5&)>&, std::pair<bool, iter::impl::GroupProducer<std::vector<int>&, main(int, char**)::<lambda(bool)> >::Group<std::vector<int, std::allocator<int> >&> >&>(<lambda(auto:5&)> &, std::pair<bool, iter::impl::GroupProducer<std::vector<int>&, main(int, char**)::<lambda(bool)> >::Group<std::vector<int, std::allocator<int> >&> > &) (__fn=..., __args#0={...}) at /usr/include/c++/8/bits/invoke.h:95
#8  0x00005555555e6d5a in std::__apply_impl<main(int, char**)::<lambda(auto:5&)>&, std::tuple<std::pair<bool, iter::impl::GroupProducer<std::vector<int>&, main(int, char**)::<lambda(bool)> >::Group<std::vector<int, std::allocator<int> >&> >&>, 0>(<lambda(auto:5&)> &, std::tuple<std::pair<bool, iter::impl::GroupProducer<std::vector<int>&, main(int, char**)::<lambda(bool)> >::Group<std::vector<int, std::allocator<int> >&> >&> &&, std::index_sequence) (__f=..., __t=...) at /usr/include/c++/8/tuple:1678
#9  0x00005555555e6d98 in std::apply<main(int, char**)::<lambda(auto:5&)>&, std::tuple<std::pair<bool, iter::impl::GroupProducer<std::vector<int>&, main(int, char**)::<lambda(bool)> >::Group<std::vector<int, std::allocator<int> >&> >&> >(<lambda(auto:5&)> &, std::tuple<std::pair<bool, iter::impl::GroupProducer<std::vector<int>&, main(int, char**)::<lambda(bool)> >::Group<std::vector<int, std::allocator<int> >&> >&> &&) (__f=..., __t=...) at /usr/include/c++/8/tuple:1687
#10 0x00005555555e6e6b in iter::impl::StarMapper<main(int, char**)::<lambda(auto:5&)>, iter::impl::Zipped<std::tuple<iter::impl::Filtered<main(int, char**)::<lambda(auto:4&)>, iter::impl::GroupProducer<std::vector<int, std::allocator<int> >&, main(int, char**)::<lambda(bool)> >&>&>, 0> >::Iterator<iter::impl::Zipped<std::tuple<iter::impl::Filtered<main(int, char**)::<lambda(auto:4&)>, iter::impl::GroupProducer<std::vector<int, std::allocator<int> >&, main(int, char**)::<lambda(bool)> >&>&>, 0> >::operator*(void) (this=0x7fffffffc6f0) at /home/miguel/Development/IPL/investigacao/vad_check/cppitertools/starmap.hpp:86
#11 0x00005555555e7998 in main (argc=3, argv=0x7fffffffd948) at /home/miguel/Development/IPL/investigacao/vad_check/src/main.cc:458

Also, wouldn't it be useful to have a function which calculates the number of elements of an iterator like std::distance(iterator.begin(), iterator.end()); ?

For comparison, the same thing in Haskell:

Prelude Data.List> x = [True,True,True,False,False,True]
Prelude Data.List> group x
[[True,True,True],[False,False],[True]]
Prelude Data.List> fmap length $ filter (!!0) $ group x
[3,1]
Prelude Data.List> sortDesc = sortBy (flip compare)
Prelude Data.List> head $ sortDesc $ fmap length $ filter (!!0) $ group x
3

count is not actually infinite

This is just a little nitpick, but I was reading you code base and realized that iter::count is doing limit checking and the explanation is a bit off

Effectively a range without a stopping point.

Although in signed integers overflow is undefined, it is defined in unsigned integers as wraparound but the below loop ends at 65534. (One before the limit)

using T = unsigned short;
    for(auto i : iter::count(T{})) {
        if(cond)
            break;
    }

I think more reasonable behaviour is just incrementing the counter by step at each iteration without doing a boundary check and let it fail if it ever hits an undefined behaviour. In here you are basically defining the behaviour.

However as I said at the beginning, this is just a little nitpick regarding the documentation and it would be still fine to keep the behaviour as it is but with proper explanation in the documentation.

VS2019 compilation errors iter::chain (fix planned for 16.4)

Hello,
few time ago I was trying to compile CppIterTools with VS2019 and I get errors with iter::chain with this kind of errors:

iterbase.hpp(94,36): error C2672:  'iter::impl::get_iters::get_begin': no matching overloaded function found
iterbase.hpp(94,1): error C2893:  Failed to specialize function template 'unknown-type iter::impl::get_iters::get_begin(T &)'
iterbase.hpp(104,43): error C2672:  'std::declval': no matching overloaded function found
iterbase.hpp(104,1): error C2893:  Failed to specialize function template '_Add_reference<_Ty,void>::_Rvalue std::declval(void) noexcept'

I have filled a bug to Microsoft and they seem to have fix the bug in their compiler on 16.4 version which isn't yet release (maybe a month or 2).
Here is the link:
https://developercommunity.visualstudio.com/content/problem/638663/vs2019-c-failed-to-specialize-sfinae-regression.html

Building and Running tests

I'm not sure how to build and test the project. I've managed to build the tests by running ./download_catch.sh and running scons in the test folder. I can run these tests manually, but I'm sure thats not the proper way.

How should the project be built and tested with Bazel and scons?

Consider overloading the "pipe" operator

Hi,

Often, I find myself mixing together cppitertools and boost.range (and – more recently – range-v3). I believe that supporting the (de-facto standard) pipe operator | would greatly improve the interoperability between the different range libraries.

Thanks.

The cmake version config file is not installed alongside the config file

According to https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html, the cmake version config file should be installed alongside the cmake config file; however:

install(EXPORT cppitertools-targets
        FILE cppitertools-config.cmake
        NAMESPACE cppitertools::
        DESTINATION ${cppitertools_INSTALL_CMAKE_DIR}/cppitertools
        )

install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cppitertools-config-version.cmake DESTINATION ${cppitertools_INSTALL_CMAKE_DIR})

is how the version file is installed -- afaict, this is a silent failure to use the version file. It seems that the DESTINATION should probably be ${cppitertools_INSTALL_CMAKE_DIR}/cppitertools, like the cppitertools-config.cmake file.

Appveyor MSVC 2019 build failing

the build log includes a CMake error:

CMake Error at C:/Program Files (x86)/CMake/share/cmake-3.15/Modules/FindPackageHandleStandardArgs.cmake:137 (message):
  Could NOT find Boost (missing: Boost_INCLUDE_DIR) (Required is at least
  version "1.60.0")
Call Stack (most recent call first):
  C:/Program Files (x86)/CMake/share/cmake-3.15/Modules/FindPackageHandleStandardArgs.cmake:378 (_FPHSA_FAILURE_MESSAGE)
  C:/Program Files (x86)/CMake/share/cmake-3.15/Modules/FindBoost.cmake:2161 (find_package_handle_standard_args)
  CMakeLists.txt:12 (find_package)

Appveyor only has Boost 1.71.0 for MSVC 2019, but the highest it has for MSVC 2017 is Boost 1.69.0.

The BOOST_ROOT environment variable in the appveyor setting is set to C:\Libraries\boost_1_64_0, but of course this only works for MSVC 2017

Both MSVC 2017 and 2019 work when they have their respective correct BOOST_ROOT

Uses features from C++14

iterbase.hpp uses std::enable_if_t, which was not added until C++14. The repository description indicates that this is a C++11 library, and nowhere in the readme does it mention that C++14 support is required.

count not working for negative non-integer step

The following statements do not work:

const std::vector<double> expected{1.0, 0.5, 0.0, -0.5, -1.0};
  std::vector<double> counted;
  for (auto c : count(1.0, -0.5)) {
    counted.push_back(c);
    if (c <= -1.0) break;
  }
  for (int i : range(expected.size()))
    EXPECT_DOUBLE_EQ(expected[i], counted[i]);

Output errors:

Expected equality of these values: expected[i] Which is: 0 counted[i] Which is: 2.1219957913605248e-313 /home/pedrogf/Projects/LightFields/ReferenceSoftware/REPO/jplm/source/Tests/ThirdParty/CppIterToolsTests.cpp:471: Failure Expected equality of these values: expected[i] Which is: -0.5 counted[i] Which is: 1.0325971998082053e-321 /home/pedrogf/Projects/LightFields/ReferenceSoftware/REPO/jplm/source/Tests/ThirdParty/CppIterToolsTests.cpp:471: Failure Expected equality of these values: expected[i] Which is: -1 counted[i] Which is: 0

However, the equivalent Python code works fine:

import itertools
for i in itertools.count(1.0, -0.5):
     print(i)
     if i <= -1:
         break

1.0 0.5 0.0 -0.5 -1.0

group_by a tuple key

Hi, I am trying to group_by a tuple key:

struct A {
    int key1;
    int key2;
    int x;
    int y;
    int value;
};

void func() {
    using namespace std;

    // inputs
    std::vector<int> uniquex{ 1, 2 };
    std::vector<int> uniquey{ 1, 2 };
    vector<A> vec{
        { 10, 9, 1, 1, 5 },     { 10, 9, 1, 2, 6 },     
        { 10, 10, 1, 1, 1 },    { 10, 10, 1, 2, 2 },
        { 10, 9, 2, 1, 7 },     { 10, 9, 2, 2, 8 },
        { 10, 10, 2, 1, 3 },    { 10, 10, 2, 2, 4 },
    };
    auto keyFunc = [](const A& a) { return make_tuple(a.key1, a.key2); };

    for (auto&& gb : iter::groupby(vec, keyFunc)) {
        std::cout << "key(" << std::get<0>(gb.first) << "," << std::get<1>(gb.first) << "): ";
                for (auto&& s : gb.second) {
                        std::cout << s.value << "  ";
                }
                std::cout << '\n';
        }

Instead of printing 2 lines, this example prints four lines. Does the groupby intent to work with group data not next to each other?

groupby support for automatic exhaustion of skipped groups

The current implementation of groupby relies on exhausting the elements of each group in order. With Python's groupby, once one tries to access the n+1th group, the nth grouping becomes invalid, so it is not necessary that random accessing of groups be supported.

The C++ implementation does not support short-circuting the evaluation of a group or skipping of a group entirely, a continue in the outer loop results in unexpected behavior. It must support the C++ equivalent of

for length, group in groupby(words, len):
    if length == 4: 
        continue
    for e in group: 
        print(e)

I'm not sure how to best handle this yet. It seems the logic will have to go either in the Group class's destructor, or in GroupBy::Iterator::operator++()

Filtering `iter::product`

Hi,

with respect to #16, I was trying to filter out the upper right corner of the matrix using iter::filter. Here's the showcase code:

int main() {

    auto range = iter::product(iter::range(10), iter::range(5));

    for (auto&& ij: iter::filter([](std::tuple<unsigned, unsigned> const& c) {return std::get<0>(c) >= std::get<1>(c);}, range))
        std::cout << std::get<0>(ij) << "," << std::get<1>(ij) << std::endl;
}

Unfortunately, this does not compile. Clang reads:

error: indirection requires pointer operand ('const iterator_type<iter::Productor<iter::Range<int>, iter::Range<int> > &>' (aka 'const iter::Productor<iter::Range<int>, iter::Range<int> >::Iterator') invalid)
                        return *this->sub_iter;

Same error if I replace iter::filter with boost::adaptors::filtered, so I presume the error should be in iter::Producter.

Thanks.

Can't dereference const zip iterator

#include <vector>

#include "zip.hpp"

int main()
{
    std::vector<int> a(1);

    const auto it = iter::zip(a).begin();
    const auto [v] = *it;

    return v;
}

[ilya@ilya-pc cppitertools]$ clang++ const_iter.cpp -I ./ -std=c++17 -fno-permissive
const_iter.cpp:11:22: error: indirection requires pointer operand ('const iter::impl::Zipped<std::tuple<std::vector<int, std::allocator > &>, 0>::Iterator<std::tuple<std::vector<int, std::allocator > &>, iterator_tuple_type, iterator_deref_tuple>' invalid)
const auto [v] = *it;

Is there a reason for Zipped::Iterator::operator*() not to be const?
https://github.com/ryanhaining/cppitertools/blob/master/zip.hpp#L90

sorted: can modify elements - why normal?

Hi. I don't understand the code in the test/test_sorted.cpp:

  std::vector<int> ns(3, 9);
  for (auto&& n : sorted(ns)) {
    n = -1;
  }
  Vec vc(3, -1);
  REQUIRE(ns == vc);

Why so? Doesn't vc must be (-1, -1)? Can you explain?

compilation of test code on OSX

Hi,
I tried to build the test code on OSX,
but a lot of the builds, which include functional.h fail with the error below.
I have not found a way to fix this yet, but if you have any suggestions where to start it would be appreciated.
Regards
Jiri

System:
$  uname -a
Darwin JiriMBP.home 14.4.0 Darwin Kernel Version 14.4.0: Thu May 28 11:35:04 PDT 2015; root:xnu-2782.30.5~1/RELEASE_X86_64 x86_64 i386 MacBookPro11,2 Darwin
$  g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.4.0
Thread model: posix
c++ -o test_combinations.o -c -g -Wall -Wextra -std=c++11 -fdiagnostics-color=always -I/usr/local/include -I. -I/Users/Jiri/Documents/lib/cpp/iter/cppitertools test_combinations.cpp
In file included from test_combinations.cpp:1:
In file included from ./helpers.hpp:4:
In file included from /Users/Jiri/Documents/lib/cpp/iter/cppitertools/iterbase.hpp:13:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:477:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:1645:31: error: no matching constructor for
      initialization of 'std::__1::vector<char, std::__1::allocator<char> >'
            ::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
                              ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:1572:18: note: in instantiation of function
      template specialization 'std::__1::allocator<std::__1::vector<char, std::__1::allocator<char> > >::construct<std::__1::vector<char,
      std::__1::allocator<char> >, iter::IteratorIterator<std::__1::__wrap_iter<std::__1::__wrap_iter<char *> *>, long>,
      iter::IteratorIterator<std::__1::__wrap_iter<std::__1::__wrap_iter<char *> *>, long> >' requested here
            {__a.construct(__p, _VSTD::forward<_Args>(__args)...);}
                 ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:1453:14: note: in instantiation of function
      template specialization 'std::__1::allocator_traits<std::__1::allocator<std::__1::vector<char, std::__1::allocator<char> > >
      >::__construct<std::__1::vector<char, std::__1::allocator<char> >, iter::IteratorIterator<std::__1::__wrap_iter<std::__1::__wrap_iter<char *> *>, long>,
      iter::IteratorIterator<std::__1::__wrap_iter<std::__1::__wrap_iter<char *> *>, long> >' requested here
            {__construct(__has_construct<allocator_type, pointer, _Args...>(),
             ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:1633:25: note: in instantiation of function
      template specialization 'std::__1::allocator_traits<std::__1::allocator<std::__1::vector<char, std::__1::allocator<char> > >
      >::construct<std::__1::vector<char, std::__1::allocator<char> >, iter::IteratorIterator<std::__1::__wrap_iter<std::__1::__wrap_iter<char *> *>, long>,
      iter::IteratorIterator<std::__1::__wrap_iter<std::__1::__wrap_iter<char *> *>, long> >' requested here
        __alloc_traits::construct(this->__alloc(),
                        ^
test_combinations.cpp:21:12: note: in instantiation of function template specialization 'std::__1::vector<std::__1::vector<char, std::__1::allocator<char> >,
      std::__1::allocator<std::__1::vector<char, std::__1::allocator<char> > >
      >::emplace_back<iter::IteratorIterator<std::__1::__wrap_iter<std::__1::__wrap_iter<char *> *>, long>,
      iter::IteratorIterator<std::__1::__wrap_iter<std::__1::__wrap_iter<char *> *>, long> >' requested here
        sc.emplace_back(std::begin(v), std::end(v));
           ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:521:5: note: candidate constructor not viable:
      no known conversion from 'iter::IteratorIterator<std::__1::__wrap_iter<std::__1::__wrap_iter<char *> *>, long>' to 'size_type' (aka 'unsigned long') for
      1st argument
    vector(size_type __n, const_reference __x);
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:555:5: note: candidate constructor not viable:
      no known conversion from 'iter::IteratorIterator<std::__1::__wrap_iter<std::__1::__wrap_iter<char *> *>, long>' to 'initializer_list<value_type>' for 1st
      argument
    vector(initializer_list<value_type> __il, const allocator_type& __a);
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:566:5: note: candidate constructor not viable:
      no known conversion from 'iter::IteratorIterator<std::__1::__wrap_iter<std::__1::__wrap_iter<char *> *>, long>' to 'const std::__1::vector<char,
      std::__1::allocator<char> >' for 1st argument
    vector(const vector& __x, const allocator_type& __a);
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:574:5: note: candidate constructor not viable:
      no known conversion from 'iter::IteratorIterator<std::__1::__wrap_iter<std::__1::__wrap_iter<char *> *>, long>' to
      'std::__1::vector<char, std::__1::allocator<char> >' for 1st argument
    vector(vector&& __x, const allocator_type& __a);
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:525:35: note: candidate template ignored:
      disabled by 'enable_if' [with _InputIterator = iter::IteratorIterator<std::__1::__wrap_iter<std::__1::__wrap_iter<char *> *>, long>]
               typename enable_if<__is_input_iterator  <_InputIterator>::value &&
                                  ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:540:35: note: candidate template ignored:
      disabled by 'enable_if' [with _ForwardIterator = iter::IteratorIterator<std::__1::__wrap_iter<std::__1::__wrap_iter<char *> *>, long>]
               typename enable_if<__is_forward_iterator<_ForwardIterator>::value &&
                                  ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:532:9: note: candidate constructor template not
      viable: requires at least 3 arguments, but 2 were provided
        vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a,
        ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:546:9: note: candidate constructor template not
      viable: requires at least 3 arguments, but 2 were provided
        vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a,
        ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:510:40: note: candidate constructor not viable:
      requires single argument '__a', but 2 arguments were provided
    _LIBCPP_INLINE_VISIBILITY explicit vector(const allocator_type& __a)
                                       ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:517:14: note: candidate constructor not viable:
      requires single argument '__n', but 2 arguments were provided
    explicit vector(size_type __n);
             ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:553:5: note: candidate constructor not viable:
      requires single argument '__il', but 2 arguments were provided
    vector(initializer_list<value_type> __il);
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:565:5: note: candidate constructor not viable:
      requires single argument '__x', but 2 arguments were provided
    vector(const vector& __x);
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:571:5: note: candidate constructor not viable:
      requires single argument '__x', but 2 arguments were provided
    vector(vector&& __x)
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:522:5: note: candidate constructor not viable:
      requires 3 arguments, but 2 were provided
    vector(size_type __n, const_reference __x, const allocator_type& __a);
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:503:5: note: candidate constructor not viable:
      requires 0 arguments, but 2 were provided
    vector()
    ^
1 error generated.
scons: *** [test_combinations.o] Error 1
scons: building terminated because of errors.

Add compiler compatibility list

Can you please add the list of compatible compilers?
VS 2013 does not support noexcept while VS 2015 finds "unknown size" errors everywhere.

Severity  Code  Description  Project  File  Line  Suppression State
Error  C2133  ' ?? ?? :: ?? ::derefers': unknown size  ...\include\cppitertools\chain.hpp  72

`iter::reversed` vs. `std::rbegin`/`std::rend`

Hi,

I don't know if this counts as a bug. However, here's the issue.
I was trying to use iter::reversed together with boost::irange. The following toy example does not compile:

#include <boost/range/irange.hpp>
#include <itertools/reversed.hpp>

int main() {

    auto r = boost::irange(0, 10);
    for (auto&& i: iter::reversed(r)) 
        std::cout << i << std::endl;

} 

the output reads:

error: no member named 'rbegin' in 'boost::integer_range<int>'
        decltype(std::declval<Container&>().rbegin());

A workaround could be to use the free functions std::rbegin and std::rend, although this would break C++11 compatibility.

Thanks.

Can't chain a `std::set` with an `std::vector`

This simple example fails to compile:

#include <stdlib.h>
#include "cppitertools/chain.hpp"

std::vector<const char *> c1 = {"a", "b", "c"};
std::set<const char *> c2 = {"d", "d", "e"};
for (auto n : iter::chain(c1, c2))
{
    std::cout << n << std::endl;
}

The following errors are raised:

in instantiation of function template specialization 'iter::impl::ChainMaker::operator()<std::vector<const char *,
      std::allocator<const char *> > &, std::set<const char *, std::less<const char *>, std::allocator<const char *> >
      &>' requested here
for (auto n : iter::chain(c1, c2)) {std::cout << n << std::endl;}
                         ^

arguments for product

  • in many use cases, the number of arguments for a function like this is known only at run time. is it possible for product to accept a vector object?
  • or add something equivalent to Python's unpacking operator (*) to cppitertools?

combination of chunked -> filter -> imap = bogus results

Hi

The following code is a minimal reproducer of an issue I'm getting.

vector<int16_t> v(10000, 0);
  auto a = iter::chunked(v,480);
  auto b = iter::filter([](auto & chunk){ return true;}, a);
  auto c = iter::imap([](auto & chunk){ cout << chunk.size() << " "; return 1;}, b);
  for(auto &&x: c);

prints

18446738293966284791 480 480 480 480 480 480 480 480 480 480 480 480 480 480 480 480 480 480 480 400

The first chunk size is always bogus. Inside the first chunk there are also bogus values.

Is this a bug, or I'm I doing something wrong ?

zip.hpp doesn't compile with gcc 8.2.1

$ g++ examples/zip_examples.cpp -I ./ -std=c++17
In file included from examples/zip_examples.cpp:1:
./zip.hpp: In instantiation of ‘class iter::impl::Zipped<std::tuple<std::vector<int, std::allocator >&, std::vector<std::__cxx11::basic_string<char, std::char_traits, std::allocator >, std::allocator<std::__cxx11::basic_string<char, std::char_traits, std::allocator > > >&>, 0, 1>::Iterator<std::tuple<std::vector<int, std::allocator >&, std::vector<std::__cxx11::basic_string<char, std::char_traits, std::allocator >, std::allocator<std::__cxx11::basic_string<char, std::char_traits, std::allocator > > >&>, iter::impl::iterator_tuple_type, iter::impl::iterator_deref_tuple>’:
examples/zip_examples.cpp:13:46: required from here
./zip.hpp:41:60: error: template parameter ‘template<class TupleType, long unsigned int ...Is> template class IteratorTuple’
template <typename TupleTypeT, template class IteratorTuple,
^~~~~~~~~~~~~
./zip.hpp:46:18: error: redeclared here as ‘template class’
friend class Iterator;
^~~~~~~~

$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.1/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /build/gcc/src/gcc/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --enable-libmpx --with-system-zlib --with-isl --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object --enable-linker-build-id --enable-lto --enable-plugin --enable-install-libiberty --with-linker-hash-style=gnu --enable-gnu-indirect-function --enable-multilib --disable-werror --enable-checking=release --enable-default-pie --enable-default-ssp --enable-cet=auto
Thread model: posix
gcc version 8.2.1 20180831 (GCC)

request zip/zip_longest functionality

Hi, good to see more Python like functions in c++.

Is it possible to have zip and zip_longest use a single iterator over an arbitrary number of containers that are only known at runtime? Just like in Python when unpacking a list of lists? It would really be helpful for me.

imap function applied multiple times

I am trying to translate this (simplified) example from python (2.7) to C++ (tried both clang 3.4 and gcc 4.7) using move-only objects.

Python snippet, prints 41 43:

import itertools as it

class MyItem:
    def __init__(self, val):
        self.val = val
    def with_val(self, val):
        self.val = val
        return self

if "__main__" == __name__:
    vec = [MyItem(41), MyItem(42), MyItem(43)]
    transformed1 = it.imap(lambda el: el.with_val(el.val + 10), vec)
    filtered = it.ifilter(lambda el: 52 != el.val, transformed1)
    transformed2 = it.imap(lambda el: el.with_val(el.val - 10), filtered)

    for el in transformed2:
        print(el.val)

C++ snippet, prints 51 53:

#include <iostream>
#include <vector>

#include "imap.hpp"
#include "filter.hpp"

class MyMoveOnly {
    int val;
public:
    MyMoveOnly() { };
    MyMoveOnly(int val) : val(val) { }
    MyMoveOnly(const MyMoveOnly&) = delete;
    MyMoveOnly& operator=(const MyMoveOnly&) = delete;
    MyMoveOnly(MyMoveOnly&& other) : val(other.val) { }
    MyMoveOnly& operator=(MyMoveOnly&& other) {
        this->val = other.val;
        return *this;
    }
    int get_val() {
        return val;
    }
    void set_val(int val) {
        this->val = val;        
    }
};

namespace it = iter;

int main() {
    // source data
    std::vector<MyMoveOnly> vec{};
    vec.emplace_back(MyMoveOnly(41));
    vec.emplace_back(MyMoveOnly(42));
    vec.emplace_back(MyMoveOnly(43));
    // some transformations
    auto transformed1 = it::imap([](MyMoveOnly& el) {
        int va = el.get_val();
        el.set_val(va + 10);
        return std::move(el);
    }, vec);
    // r-value ref is used here because l-value ref won't compile
    auto filtered = it::filter([](MyMoveOnly&& el) {
        return 52 != el.get_val();
    }, transformed1);
    auto transformed2 = it::imap([](MyMoveOnly& el) {
        int va = el.get_val();
        el.set_val(va - 10);
        return std::move(el);
    }, filtered);
    // print data
    for (auto&& el : transformed2) {
        std::cout << el.get_val() << std::endl;
    }

    return 0;
}

I wasn't sure that this example will compile (because of non-copyable objects), it actually compiles and runs, but the first transformation is applied twice for each element. I am not sure whether this is intended behaviour, but it is definitely contr-intuitive because single foreach over the transformed sequence caused multiple applyings of imap function.

Product begin won't compile

I was able to get the begin iterator for range to work:

auto r = iter::range(5);
auto first = r.begin();

But I can't get product to compile:

std::string s = "abc";
auto p = iter::product(s,s);
auto first = p.begin();

This was compiled on Visual Studio 2017.
Here's the error message:

1>main.cpp
1>d:\visual studio 2017\itertools_test\cppitertools\internal\iterbase.hpp(75): error C2672: 'iter::impl::get_iters::get_begin': no matching overloaded function found
1>d:\visual studio 2017\itertools_test\cppitertools\internal\iterbase.hpp(85): note: see reference to alias template instantiation 'iterator_type' being compiled
1>d:\visual studio 2017\itertools_test\cppitertools\product.hpp(39): note: see reference to alias template instantiation 'iterator_deref' being compiled
1>d:\visual studio 2017\itertools_test\cppitertools\product.hpp(54): note: see reference to alias template instantiation 'ProdIterDeref<std::basic_string<char,std::char_traits,std::allocator>&>' being compiled
1>d:\visual studio 2017\itertools_test\product_test\product_test\main.cpp(18): note: see reference to class template instantiation 'iter::impl::Productor<std::string &,std::string &>::IteratorTempl<Container,iter::impl::Productor<std::string &>::IteratorTempl<Container,iter::impl::Productor<>::Iterator>>' being compiled
1> with
1> [
1> Container=std::string &
1> ]
1>d:\visual studio 2017\itertools_test\cppitertools\internal\iterbase.hpp(75): error C2893: Failed to specialize function template 'unknown-type iter::impl::get_iters::get_begin(T &)'
1>d:\visual studio 2017\itertools_test\cppitertools\internal\iterbase.hpp(75): note: With the following template arguments:
1>d:\visual studio 2017\itertools_test\cppitertools\internal\iterbase.hpp(75): note: 'T=add_rvalue_reference<_Ty>::type'
1>d:\visual studio 2017\itertools_test\cppitertools\internal\iterbase.hpp(85): error C2672: 'std::declval': no matching overloaded function found
1>d:\visual studio 2017\itertools_test\cppitertools\internal\iterbase.hpp(85): error C2893: Failed to specialize function template 'add_rvalue_reference<_Ty>::type std::declval(void) noexcept'
1>d:\visual studio 2017\itertools_test\cppitertools\internal\iterbase.hpp(85): note: With the following template arguments:
1>d:\visual studio 2017\itertools_test\cppitertools\internal\iterbase.hpp(85): note: '_Ty=unknown-type &'
1>d:\visual studio 2017\itertools_test\cppitertools\product.hpp(39): error C3546: '...': there are no parameter packs available to expand
1>d:\visual studio 2017\itertools_test\cppitertools\product.hpp(54): error C3203: 'tuple': unspecialized class template can't be used as a template argument for template parameter '_Ty', expected a real type
1>d:\visual studio 2017\itertools_test\cppitertools\product.hpp(58): error C2512: 'std::is_same<unknown-type,unknown-type>': no appropriate default constructor available
1>d:\visual studio 2017\itertools_test\cppitertools\product.hpp(58): note: The target type has no constructors
1>d:\visual studio 2017\itertools_test\cppitertools\product.hpp(108): error C3203: 'tuple': unspecialized class template can't be used as a template argument for template parameter 'T', expected a real type

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.