1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#pragma once


#include <iterator><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <ranges><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <concepts><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <algorithm><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.


#include "internal/dev_env.hpp"
#include "internal/types.hpp"


namespace uni {


template<class Size = internal::size_t>
struct next_combination {
    using size_type = Size;

  private:
    size_type _size;

  public:
    next_combination(const size_type size) : _size(size) {};

    auto size() noexcept(NO_EXCEPT) { return this->_size; }

    template<std::ranges::bidirectional_range R>
    auto operator()(R&& range) const noexcept(NO_EXCEPT) { return this->operator()(ALL(range)); }

    template<std::bidirectional_iterator I, std::sentinel_for<I> S>
    auto operator()(I first, S last) const noexcept(NO_EXCEPT) {
        auto subset = std::ranges::next(first, this->size());

        if(first == last || first == subset || last == subset) return false;

        auto src = subset;
        while (first != src) {
            --src;

            if (*src < *std::ranges::prev(last)) {
                auto dest = subset;
                while (*src >= *dest) ++dest;

                std::ranges::iter_swap(src, dest);
                std::ranges::rotate(std::ranges::next(src), std::ranges::next(dest), last);
                std::ranges::rotate(subset, std::ranges::next(subset, std::ranges::distance(dest, last) - 1), last);

                return true;
            }
        }

        std::ranges::rotate(first, subset, last);

        return false;
    }
};


}  // namespace uni