import interface Hashable from hash;
import fn hash from hash;
import fn { iterator, next, is_consumed, range } from range;

class HashSet<V> {
    buckets: Array<Array<'V [Hashable]>>;
}

fn<T> init(set: @HashSet<'T [Hashable]>, size: Int) {
    let _buckets = set.buckets();
    _buckets.reserve(*size);

    for i in range(0, *size) {
        _buckets.push(arr<'T>());
    }
}

fn<T> hashset() -> HashSet<'T [Hashable]> {
    let res = HashSet(arr<Array<'T>>());
    res.init(10);

    return move(res);
}

fn<T> rehash(set: @HashSet<'T [Hashable]>) {
    let b = set.buckets();
    let size = b.len();

    let aux = HashSet(arr<Array<'T>>());
    aux.init(size * 2);

    for bucket in set.buckets() {
        for elem in bucket {
            aux.add(move(elem));
        }
    }

    set.buckets() := move(aux.buckets());
}

fn<T> add(set: @HashSet<'T [Hashable]>, elem: 'T) {
    let b = set.buckets();
    let size = b.len();
    let pos = hash(*elem) % size;

    b[*pos].push(move(elem));

    if b[*pos].len() > size {
        set.rehash();
    }
}

fn<T> contains(set: @HashSet<'T [Hashable]>, elem: @'T) -> Bool {
    let b = set.buckets();
    let size = b.len();
    let pos = hash(*elem) % size;

    for i in b[*pos] {
        if i == elem {
            return true;
        }
    }

    return false;
}