123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- package slice
- import "base:runtime"
- // An in-place permutation iterator.
- Permutation_Iterator :: struct($T: typeid) {
- index: int,
- slice: []T,
- counters: []int,
- }
- /*
- Make an iterator to permute a slice in-place.
- *Allocates Using Provided Allocator*
- This procedure allocates some state to assist in permutation and does not make
- a copy of the underlying slice. If you want to permute a slice without altering
- the underlying data, use `clone` to create a copy, then permute that instead.
- Inputs:
- - slice: The slice to permute.
- - allocator: (default is context.allocator)
- Returns:
- - iter: The iterator, to be passed to `permute`.
- - error: An `Allocator_Error`, if allocation failed.
- */
- make_permutation_iterator :: proc(
- slice: []$T,
- allocator := context.allocator,
- ) -> (
- iter: Permutation_Iterator(T),
- error: runtime.Allocator_Error,
- ) #optional_allocator_error {
- iter.slice = slice
- iter.counters = make([]int, len(iter.slice), allocator) or_return
- return
- }
- /*
- Free the state allocated by `make_permutation_iterator`.
- Inputs:
- - iter: The iterator created by `make_permutation_iterator`.
- - allocator: The allocator used to create the iterator. (default is context.allocator)
- */
- destroy_permutation_iterator :: proc(
- iter: Permutation_Iterator($T),
- allocator := context.allocator,
- ) {
- delete(iter.counters, allocator = allocator)
- }
- /*
- Permute a slice in-place.
- Note that the first iteration will always be the original, unpermuted slice.
- Inputs:
- - iter: The iterator created by `make_permutation_iterator`.
- Returns:
- - ok: True if the permutation succeeded, false if the iteration is complete.
- */
- permute :: proc(iter: ^Permutation_Iterator($T)) -> (ok: bool) {
- // This is an iterative, resumable implementation of Heap's algorithm.
- //
- // The original algorithm was described by B. R. Heap as "Permutations by
- // interchanges" in The Computer Journal, 1963.
- //
- // This implementation is based on the nonrecursive version described by
- // Robert Sedgewick in "Permutation Generation Methods" which was published
- // in ACM Computing Surveys in 1977.
- i := iter.index
- if i == 0 {
- iter.index = 1
- return true
- }
- n := len(iter.counters)
- #no_bounds_check for i < n {
- if iter.counters[i] < i {
- if i & 1 == 0 {
- iter.slice[0], iter.slice[i] = iter.slice[i], iter.slice[0]
- } else {
- iter.slice[iter.counters[i]], iter.slice[i] = iter.slice[i], iter.slice[iter.counters[i]]
- }
- iter.counters[i] += 1
- i = 1
- break
- } else {
- iter.counters[i] = 0
- i += 1
- }
- }
- if i == n {
- return false
- }
- iter.index = i
- return true
- }
|