Skip to content

REAL zip iterator, that will be considered as an Iterator by other C++ code.

License

Notifications You must be signed in to change notification settings

andreysolovyev381/zip_in_cpp

Repository files navigation

Zip in C++

Reasoning and Some info

I like small useful snippets, like this one. Let myself have an entertaining night while coding this exercise.

  • Standard and Compilers: works like a charm in 17 and 20 (in case you are not yet in 23, but when you are there, you should take a look at respective page at cppref). Anyway, this impl compiles ok by gcc and clang on Linux - see GH Actions for this repo. Dependencies: header only, STL only.
  • Iterator's big five is properly defined in the class: value_type, reference, difference_type, pointer, iterator_category. So other C++ code will consider this zip_iterator as an iterator as well.
  • Lots of concept (C++20) and SFINAE (C++17) guards will fail the attempts of enlightened user to get an iterator from type void. Compile with WRONG_ITERATOR_COMPILE_FAILURE to see compile-time errors generated by the tests, or simply uncomment this #define in the test file.
  • UI is simple - call 'zip' using either arbitrary number of containers or arbitrary number of iterators as the arguments. If there are containers, then 'zip' provides A PAIR of iterators for each container, begin() and end() respectively.
  • It is tested - see the file.
  • Problems - move_iterators work by copying r_value_references 🙈 Maybe will fix it later 🤓

Usage

Pretty much straightforward, see the test file. Here is the most vivid example:

	std::vector<int> v{ 1,2,3,4,5 };
	std::map<int, std::string> m { {1, "one"s}, {2, "two"s}, {3, "three"s}, };
	std::string s { "abcdefghhlk" };
	
	/// Here it is, see the for loop expr
	for (auto const& [i, pair, ch] : itertools::zip(v, m, s)) {
		std::cout << i << ' ' << pair.first << ' ' << pair.second << ' ' << ch << '\n';
	}

Another example, if zipping iterators instead of containers:

	struct TestStruct {
		std::map<int, std::string> m { {1, "one"s}, {2, "two"s}, {3, "three"s}, };
		auto begin() const { return m.begin(); }
		auto end() const { return m.end(); }
	};
	TestStruct test_struct;
	std::vector<int> v{ 1,2,3,4,5 };
	std::string s { "abcdefghlk" };

	/// Here it is, zipping different input iterators - normal, constant and reverse
	auto begin = itertools::zip(v.cbegin(), s.crbegin(), test_struct.begin());
	auto end = itertools::zip(v.cend(), s.crend(), test_struct.end());

	for (auto itb = begin; itb != end; ++itb ) {
		auto const &[normal, const_reverse, const_normal] = itb;
		auto const &[i, c] = const_normal;
		std::cout << normal << ' ' << const_reverse << ' ' << i << ' ' << c << '\n';
	}

Disclaimer

Feel free to use it for your needs at your own risk. No guarantees of any kind is given :)

License

MIT License