#ifndef ITER_PERMUTATIONS_HPP_ #define ITER_PERMUTATIONS_HPP_ #include "internal/iterbase.hpp" #include "internal/iteratoriterator.hpp" #include #include #include #include #include namespace iter { namespace impl { template class Permuter; } template impl::Permuter permutations(Container&&); template impl::Permuter> permutations( std::initializer_list); } template class iter::impl::Permuter { private: Container container; using IndexVector = std::vector>; using Permutable = IterIterWrapper; friend Permuter iter::permutations(Container&&); template friend Permuter> iter::permutations( std::initializer_list); Permuter(Container&& in_container) : container(std::forward(in_container)) {} public: Permuter(Permuter&&) = default; 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 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