#include <inttypes.h>
#include <stdio.h>

#include "core/HashMap.h"
#include "core/Random.h"
#include "core/Utility.h"

HASHMAP(int, int, Int)
HASHMAP_SOURCE(int, int, Int)

static i64 testSearch(const HashMapInt* m) {
    i64 nanos = getNanos();
    volatile int sum = 0;
    for(int i = 0; i < 10'000; i++) {
        for(int k = -5000; k < 5000; k++) {
            const int* s = searchHashMapKeyInt(m, i + k);
            if(s != nullptr) {
                sum = sum + *s;
            }
        }
    }
    return getNanos() - nanos;
}

static i64 testEmptySearch(const HashMapInt* m) {
    i64 nanos = getNanos();
    volatile int sum = 0;
    for(int i = 0; i < 100'000'000; i++) {
        const int* s = searchHashMapKeyInt(m, -i);
        if(s != nullptr) {
            sum = sum + *s;
        }
    }
    return getNanos() - nanos;
}

static void fillOrder(HashMapInt* m) {
    i64 nanos = getNanos();
    for(int i = 0; i < 10'000; i++) {
        *putHashMapKeyInt(m, i) = i * i;
    }
    printf("Fill Order: %" PRId64 "ns\n", getNanos() - nanos);
}

static void fillChaos(HashMapInt* m) {
    i64 nanos = getNanos();
    Random random;
    initRandom(&random, 0);
    for(int i = 0; i < 10'000; i++) {
        int r = randomI32(&random, 0, 10'000);
        *putHashMapKeyInt(m, r) = r * r;
    }
    printf("Fill Chaos: %" PRId64 "ns\n", getNanos() - nanos);
}

static i64 average(HashMapInt* m, i64 (*f)(const HashMapInt* m), int n) {
    i64 sum = 0;
    for(int i = 0; i < n; i++) {
        sum += f(m);
    }
    return (i64)(sum / (n * 1'000'000));
}

static void order(int n) {
    HashMapInt m;
    initHashMapInt(&m);
    fillOrder(&m);
    puts("Order Probing");
    printf("Search | %" PRId64 " ms\n", average(&m, testSearch, n));
    printf("EmptySearch | %" PRId64 " ms\n", average(&m, testEmptySearch, n));
    destroyHashMapInt(&m);
}

static void chaos(int n) {
    HashMapInt m;
    initHashMapInt(&m);
    fillChaos(&m);
    puts("Chaos Probing");
    printf("Search | %" PRId64 " ms\n", average(&m, testSearch, n));
    printf("EmptySearch | %" PRId64 " ms\n", average(&m, testEmptySearch, n));
    destroyHashMapInt(&m);
}

int main() {
    order(3);
    chaos(3);
    return 0;
}