#ifndef TRI_LAB_COMMON_H
#define TRI_LAB_COMMON_H

#include <stddef.h>
#include <stdint.h>

typedef struct {
    unsigned long long comparisons;
    unsigned long long moves;
    unsigned long long swaps;
    int error;
} SortStats;

typedef void (*SortFunction)(int *, size_t, SortStats *, uint32_t *);

static inline int sort_lt(int a, int b, SortStats *s) { s->comparisons++; return a < b; }
static inline int sort_le(int a, int b, SortStats *s) { s->comparisons++; return a <= b; }
static inline int sort_gt(int a, int b, SortStats *s) { s->comparisons++; return a > b; }
static inline int sort_ge(int a, int b, SortStats *s) { s->comparisons++; return a >= b; }

static inline void sort_swap(int *a, int *b, SortStats *s) {
    if (a != b) {
        int tmp = *a;
        *a = *b;
        *b = tmp;
        s->swaps++;
        s->moves += 3;
    }
}

static inline uint32_t sort_rng_next(uint32_t *state) {
    uint32_t x = *state;
    if (x == 0U) x = 0x6D2B79F5U;
    x ^= x << 13;
    x ^= x >> 17;
    x ^= x << 5;
    *state = x;
    return x;
}

void sort_insertion(int *, size_t, SortStats *, uint32_t *);
void sort_bubble(int *, size_t, SortStats *, uint32_t *);
void sort_selection(int *, size_t, SortStats *, uint32_t *);
void sort_shell(int *, size_t, SortStats *, uint32_t *);
void sort_merge(int *, size_t, SortStats *, uint32_t *);
void sort_quick_first(int *, size_t, SortStats *, uint32_t *);
void sort_quick_middle(int *, size_t, SortStats *, uint32_t *);
void sort_quick_random(int *, size_t, SortStats *, uint32_t *);
void sort_heap(int *, size_t, SortStats *, uint32_t *);
void sort_counting(int *, size_t, SortStats *, uint32_t *);
void sort_radix(int *, size_t, SortStats *, uint32_t *);

#endif
