| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 |
- /* GNU LGPL version 2 (or later) - see LICENSE file for details */
- #include "config.h"
- #include <assert.h>
- #include <ccan/build_assert/build_assert.h>
- #include <ccan/mem/mem.h>
- #include <ccan/permutation/permutation.h>
- unsigned long long permutation_count(int n)
- {
- unsigned long long count = 1;
- int i;
- for (i = 1; i <=n; i++)
- count *= i;
- return count;
- }
- struct plain_change_state {
- int8_t dir : 2;
- uint8_t pos : PERMUTATION_MAX_SHIFT;
- };
- static inline struct plain_change_state *get_state(struct permutation *pi)
- {
- BUILD_ASSERT(sizeof(struct plain_change_state) == 1);
- return (struct plain_change_state *)(pi + 1) + pi->n;
- }
- struct permutation *permutation_new(int n)
- {
- struct permutation *pi;
- int i;
- struct plain_change_state *xs;
- assert(n <= PERMUTATION_MAX_ITEMS);
- pi = malloc(sizeof(*pi) + 2 * n);
- if (!pi)
- return NULL;
- pi->n = n;
- xs = get_state(pi);
- for (i = 0; i < pi->n; i++) {
- pi->v[i] = i;
- xs[i].pos = i;
- xs[i].dir = (i == 0) ? 0 : -1;
- }
- return pi;
- }
- permutation_swap_t permutation_change(struct permutation *pi)
- {
- int v, w, i;
- int a, b, vdir;
- struct plain_change_state *xs = get_state(pi);
- if (!pi->n)
- return 0;
- for (v = pi->n - 1; v > 0; v--) {
- if (xs[v].dir)
- break;
- }
- a = xs[v].pos;
- vdir = xs[v].dir;
- if (!vdir)
- return 0;
- b = a + vdir;
- w = pi->v[b];
- pi->v[a] = w;
- pi->v[b] = v;
- xs[v].pos = b;
- xs[w].pos = a;
- /* If we reach the end, or the next item is larger, set
- * direction to 0 */
- if ((b == 0) || (b == (pi->n-1))
- || (pi->v[b + vdir] > v))
- xs[v].dir = 0;
- /* Reset direction on all elements greater than the chosen one */
- for (i = v + 1; i < pi->n; i++) {
- if (xs[i].pos < b)
- xs[i].dir = 1;
- else
- xs[i].dir = -1;
- }
- return (b * PERMUTATION_MAX_ITEMS) + a;
- }
|