// @file permutation.003.cpp
// @ingroup experimental
// Generate successive k-length permutations from sequence.
// @note Alternate iteration; size_t version.
// @date 10/25/2025
#include <algorithm>
#include <vector>
#include <iostream>
#include <cassert>
template<typename T>
struct Permutation {
typedef std::vector<T> result_type;
template<typename InputIt>
Permutation(InputIt, InputIt, size_t k);
bool done() const;
result_type next();
private:
void m_next_permutation();
std::vector<T> m_items;
std::vector<size_t> m_cycle;
bool m_done;
};
template<typename T>
template<typename InputIt>
Permutation<T>::Permutation(InputIt first, InputIt last, size_t k)
: m_items(first, last), m_done(k > m_items.size())
{
if (this->done())
return;
for (size_t i = 0; i < k; i++)
m_cycle.push_back(i);
}
template<typename T>
bool Permutation<T>::done() const
{
return m_done;
}
template<typename T>
auto Permutation<T>::next() -> result_type
{
assert(!this->done());
auto first = m_items.begin();
result_type result(first, std::next(first, m_cycle.size()));
m_next_permutation();
return result;
}
template<typename T>
void Permutation<T>::m_next_permutation()
{
size_t n = m_items.size();
size_t k = m_cycle.size();
for (size_t i = k-1; i != static_cast<size_t>(-1); i--)
{
if (++m_cycle[i] < n)
{
std::swap(m_items[i], m_items[m_cycle[i]]);
return;
}
m_cycle[i] = i;
auto first = std::next(m_items.begin(), i);
std::rotate(first, std::next(first, 1), m_items.end());
}
m_done = true;
}
template<typename InputIt>
auto make_permutation(InputIt first, InputIt last, size_t k)
{
typedef typename std::iterator_traits<InputIt>::value_type value_type;
return Permutation<value_type>(first, last, k);
}
template<typename InputIt>
auto make_permutation(InputIt first, InputIt last)
{
return make_permutation(first, last, std::distance(first, last));
}
//
// Main.
//
template<typename T>
void show(Permutation<T>&& permutation)
{
while (!permutation.done())
{
for (auto x : permutation.next())
std::cout << x;
std::cout << ' ';
}
std::cout << std::endl;
}
int main()
{
// Expect: AB AC AD BA BC BD CA CB CD DA DB DC
std::string s{"ABCD"};
show(make_permutation(s.begin(), s.end(), 2));
// Expect: 012 021 102 120 201 210
std::vector<int> v{0, 1, 2};
show(make_permutation(v.begin(), v.end()));
}
Ly8gQGZpbGUgcGVybXV0YXRpb24uMDAzLmNwcAovLyBAaW5ncm91cCBleHBlcmltZW50YWwKLy8gR2VuZXJhdGUgc3VjY2Vzc2l2ZSBrLWxlbmd0aCBwZXJtdXRhdGlvbnMgZnJvbSBzZXF1ZW5jZS4KLy8gQG5vdGUgQWx0ZXJuYXRlIGl0ZXJhdGlvbjsgc2l6ZV90IHZlcnNpb24uCi8vIEBkYXRlIDEwLzI1LzIwMjUKCiNpbmNsdWRlIDxhbGdvcml0aG0+CiNpbmNsdWRlIDx2ZWN0b3I+CiNpbmNsdWRlIDxpb3N0cmVhbT4KI2luY2x1ZGUgPGNhc3NlcnQ+Cgp0ZW1wbGF0ZTx0eXBlbmFtZSBUPgpzdHJ1Y3QgUGVybXV0YXRpb24gewogICAgdHlwZWRlZiBzdGQ6OnZlY3RvcjxUPiByZXN1bHRfdHlwZTsKCiAgICB0ZW1wbGF0ZTx0eXBlbmFtZSBJbnB1dEl0PgogICAgUGVybXV0YXRpb24oSW5wdXRJdCwgSW5wdXRJdCwgc2l6ZV90IGspOwogICAgYm9vbCBkb25lKCkgY29uc3Q7CiAgICByZXN1bHRfdHlwZSBuZXh0KCk7Cgpwcml2YXRlOgogICAgdm9pZCBtX25leHRfcGVybXV0YXRpb24oKTsKCiAgICBzdGQ6OnZlY3RvcjxUPiAgICAgIG1faXRlbXM7CiAgICBzdGQ6OnZlY3RvcjxzaXplX3Q+IG1fY3ljbGU7CiAgICBib29sICAgICAgICAgICAgICAgIG1fZG9uZTsKfTsKCnRlbXBsYXRlPHR5cGVuYW1lIFQ+CnRlbXBsYXRlPHR5cGVuYW1lIElucHV0SXQ+ClBlcm11dGF0aW9uPFQ+OjpQZXJtdXRhdGlvbihJbnB1dEl0IGZpcnN0LCBJbnB1dEl0IGxhc3QsIHNpemVfdCBrKQo6IG1faXRlbXMoZmlyc3QsIGxhc3QpLCBtX2RvbmUoayA+IG1faXRlbXMuc2l6ZSgpKQp7CiAgICBpZiAodGhpcy0+ZG9uZSgpKQogICAgICAgIHJldHVybjsKICAgIGZvciAoc2l6ZV90IGkgPSAwOyBpIDwgazsgaSsrKQogICAgICAgIG1fY3ljbGUucHVzaF9iYWNrKGkpOwp9Cgp0ZW1wbGF0ZTx0eXBlbmFtZSBUPgpib29sIFBlcm11dGF0aW9uPFQ+Ojpkb25lKCkgY29uc3QKewogICAgcmV0dXJuIG1fZG9uZTsKfQoKdGVtcGxhdGU8dHlwZW5hbWUgVD4KYXV0byBQZXJtdXRhdGlvbjxUPjo6bmV4dCgpIC0+IHJlc3VsdF90eXBlCnsKICAgIGFzc2VydCghdGhpcy0+ZG9uZSgpKTsKICAgIGF1dG8gZmlyc3QgPSBtX2l0ZW1zLmJlZ2luKCk7CiAgICByZXN1bHRfdHlwZSByZXN1bHQoZmlyc3QsIHN0ZDo6bmV4dChmaXJzdCwgbV9jeWNsZS5zaXplKCkpKTsKICAgIG1fbmV4dF9wZXJtdXRhdGlvbigpOwogICAgcmV0dXJuIHJlc3VsdDsKfQoKdGVtcGxhdGU8dHlwZW5hbWUgVD4Kdm9pZCBQZXJtdXRhdGlvbjxUPjo6bV9uZXh0X3Blcm11dGF0aW9uKCkKewogICAgc2l6ZV90IG4gPSBtX2l0ZW1zLnNpemUoKTsKICAgIHNpemVfdCBrID0gbV9jeWNsZS5zaXplKCk7CgogICAgZm9yIChzaXplX3QgaSA9IGstMTsgaSAhPSBzdGF0aWNfY2FzdDxzaXplX3Q+KC0xKTsgaS0tKQogICAgewogICAgICAgIGlmICgrK21fY3ljbGVbaV0gPCBuKQogICAgICAgIHsKICAgICAgICAgICAgc3RkOjpzd2FwKG1faXRlbXNbaV0sIG1faXRlbXNbbV9jeWNsZVtpXV0pOwogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIG1fY3ljbGVbaV0gPSBpOwogICAgICAgIGF1dG8gZmlyc3QgPSBzdGQ6Om5leHQobV9pdGVtcy5iZWdpbigpLCBpKTsKICAgICAgICBzdGQ6OnJvdGF0ZShmaXJzdCwgc3RkOjpuZXh0KGZpcnN0LCAxKSwgbV9pdGVtcy5lbmQoKSk7CiAgICB9CiAgICBtX2RvbmUgPSB0cnVlOwp9Cgp0ZW1wbGF0ZTx0eXBlbmFtZSBJbnB1dEl0PgphdXRvIG1ha2VfcGVybXV0YXRpb24oSW5wdXRJdCBmaXJzdCwgSW5wdXRJdCBsYXN0LCBzaXplX3QgaykKewogICAgdHlwZWRlZiB0eXBlbmFtZSBzdGQ6Oml0ZXJhdG9yX3RyYWl0czxJbnB1dEl0Pjo6dmFsdWVfdHlwZSB2YWx1ZV90eXBlOwogICAgcmV0dXJuIFBlcm11dGF0aW9uPHZhbHVlX3R5cGU+KGZpcnN0LCBsYXN0LCBrKTsKfQoKdGVtcGxhdGU8dHlwZW5hbWUgSW5wdXRJdD4KYXV0byBtYWtlX3Blcm11dGF0aW9uKElucHV0SXQgZmlyc3QsIElucHV0SXQgbGFzdCkKewogICAgcmV0dXJuIG1ha2VfcGVybXV0YXRpb24oZmlyc3QsIGxhc3QsIHN0ZDo6ZGlzdGFuY2UoZmlyc3QsIGxhc3QpKTsKfQoKLy8KLy8gTWFpbi4KLy8KCnRlbXBsYXRlPHR5cGVuYW1lIFQ+CnZvaWQgc2hvdyhQZXJtdXRhdGlvbjxUPiYmIHBlcm11dGF0aW9uKQp7CiAgICB3aGlsZSAoIXBlcm11dGF0aW9uLmRvbmUoKSkKICAgIHsKICAgICAgICBmb3IgKGF1dG8geCA6IHBlcm11dGF0aW9uLm5leHQoKSkKICAgICAgICAgICAgc3RkOjpjb3V0IDw8IHg7CiAgICAgICAgc3RkOjpjb3V0IDw8ICcgJzsKICAgIH0KICAgIHN0ZDo6Y291dCA8PCBzdGQ6OmVuZGw7Cn0KCmludCBtYWluKCkKewogICAgLy8gRXhwZWN0OiBBQiBBQyBBRCBCQSBCQyBCRCBDQSBDQiBDRCBEQSBEQiBEQwogICAgc3RkOjpzdHJpbmcgc3siQUJDRCJ9OwogICAgc2hvdyhtYWtlX3Blcm11dGF0aW9uKHMuYmVnaW4oKSwgcy5lbmQoKSwgMikpOwoKICAgIC8vIEV4cGVjdDogMDEyIDAyMSAxMDIgMTIwIDIwMSAyMTAKICAgIHN0ZDo6dmVjdG9yPGludD4gdnswLCAxLCAyfTsKICAgIHNob3cobWFrZV9wZXJtdXRhdGlvbih2LmJlZ2luKCksIHYuZW5kKCkpKTsKfQ==