module Std::Map {

extern func bux_hash_bytes(ptr: *void, size: uint) -> uint;
extern func bux_hash_string(s: String) -> uint;

// ---------------------------------------------------------------------------
// Generic Map<K, V> — works with value-type keys (int, float, etc.)
// For String keys, use StringMap below.
// ---------------------------------------------------------------------------

struct MapEntry<K, V> {
    key: K,
    value: V,
    occupied: bool,
}

struct Map<K, V> {
    entries: *MapEntry<K, V>,
    cap: uint,
    len: uint,
}

func Map_New<K, V>(cap: uint) -> Map<K, V> {
    let total: uint = cap * sizeof(MapEntry<K, V>);
    let data: *MapEntry<K, V> = bux_alloc(total) as *MapEntry<K, V>;
    var i: uint = 0;
    while i < cap {
        data[i].occupied = false;
        i = i + 1;
    }
    return Map<K, V> { entries: data, cap: cap, len: 0 };
}

func Map_Set<K, V>(m: *Map<K, V>, key: K, value: V) {
    var keyPtr: *K = &key;
    let hash: uint = bux_hash_bytes(keyPtr as *void, sizeof(K));
    var idx: uint = hash % m.cap;
    while m.entries[idx].occupied {
        if m.entries[idx].key == key {
            m.entries[idx].value = value;
            return;
        }
        idx = (idx + 1) % m.cap;
    }
    m.entries[idx].key = key;
    m.entries[idx].value = value;
    m.entries[idx].occupied = true;
    m.len = m.len + 1;
}

func Map_Get<K, V>(m: *Map<K, V>, key: K) -> V {
    var keyPtr: *K = &key;
    let hash: uint = bux_hash_bytes(keyPtr as *void, sizeof(K));
    var idx: uint = hash % m.cap;
    while m.entries[idx].occupied {
        if m.entries[idx].key == key {
            return m.entries[idx].value;
        }
        idx = (idx + 1) % m.cap;
    }
    // Return zero value for missing key
    var zero: V = 0 as V;
    return zero;
}

func Map_Has<K, V>(m: *Map<K, V>, key: K) -> bool {
    var keyPtr: *K = &key;
    let hash: uint = bux_hash_bytes(keyPtr as *void, sizeof(K));
    var idx: uint = hash % m.cap;
    while m.entries[idx].occupied {
        if m.entries[idx].key == key {
            return true;
        }
        idx = (idx + 1) % m.cap;
    }
    return false;
}

func Map_Len<K, V>(m: *Map<K, V>) -> uint {
    return m.len;
}

func Map_Free<K, V>(m: *Map<K, V>) {
    bux_free(m.entries as *void);
    m.entries = null as *MapEntry<K, V>;
    m.cap = 0;
    m.len = 0;
}

// ---------------------------------------------------------------------------
// StringMap<V> — specialized Map for String keys, using strcmp
// ---------------------------------------------------------------------------

struct StringMapEntry<V> {
    key: String,
    value: V,
    occupied: bool,
}

struct StringMap<V> {
    entries: *StringMapEntry<V>,
    cap: uint,
    len: uint,
}

func StringMap_New<V>(cap: uint) -> StringMap<V> {
    let total: uint = cap * sizeof(StringMapEntry<V>);
    let data: *StringMapEntry<V> = bux_alloc(total) as *StringMapEntry<V>;
    var i: uint = 0;
    while i < cap {
        data[i].occupied = false;
        i = i + 1;
    }
    return StringMap<V> { entries: data, cap: cap, len: 0 };
}

func StringMap_Set<V>(m: *StringMap<V>, key: String, value: V) {
    let hash: uint = bux_hash_string(key);
    var idx: uint = hash % m.cap;
    while m.entries[idx].occupied {
        if String_Eq(m.entries[idx].key, key) {
            m.entries[idx].value = value;
            return;
        }
        idx = (idx + 1) % m.cap;
    }
    m.entries[idx].key = key;
    m.entries[idx].value = value;
    m.entries[idx].occupied = true;
    m.len = m.len + 1;
}

func StringMap_Get<V>(m: *StringMap<V>, key: String) -> V {
    let hash: uint = bux_hash_string(key);
    var idx: uint = hash % m.cap;
    while m.entries[idx].occupied {
        if String_Eq(m.entries[idx].key, key) {
            return m.entries[idx].value;
        }
        idx = (idx + 1) % m.cap;
    }
    var zero: V = 0 as V;
    return zero;
}

func StringMap_Has<V>(m: *StringMap<V>, key: String) -> bool {
    let hash: uint = bux_hash_string(key);
    var idx: uint = hash % m.cap;
    while m.entries[idx].occupied {
        if String_Eq(m.entries[idx].key, key) {
            return true;
        }
        idx = (idx + 1) % m.cap;
    }
    return false;
}

func StringMap_Len<V>(m: *StringMap<V>) -> uint {
    return m.len;
}

func StringMap_Free<V>(m: *StringMap<V>) {
    bux_free(m.entries as *void);
    m.entries = null as *StringMapEntry<V>;
    m.cap = 0;
    m.len = 0;
}

}