// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.

module builtin

/*
	This is work in progress.
	A very early test version of the hashmap with a fixed size.
	Only works with string keys and int values for now.
	
	I added this to improve performance of the V compiler,
	which uses lots of O(log n) map get's. Turned out with N < 10 000
	the performance gains are basically non-existent.
*/

struct hashmap {
	cap          int
	keys         []string
	table        []hashmapentry
	elm_size int
pub:
	nr_collisions int
}

struct hashmapentry {
        key string
        val int
        next &hashmapentry  // linked list for collisions
}

const (
	min_cap = 2 << 10
	max_cap = 2 << 20
)

fn new_hashmap(planned_nr_items int) hashmap {
	mut cap := planned_nr_items * 5
	if cap < min_cap {
		cap = min_cap
	}	
	if cap > max_cap {
		cap = max_cap
	}	
	return hashmap{
		cap: cap
		elm_size: 4
		table: make(cap, cap, sizeof(hashmapentry))
	}	
}	

fn (m mut hashmap) set(key string, val int) {
	mut hash := int(b_fabs( key.hash() ))
	idx := hash % m.cap
	if m.table[idx].key.len != 0 {
		//println('\nset() idx=$idx key="$key" hash="$hash" val=$val')
		m.nr_collisions++
		//println('collision:' + m.table[idx].key)
		mut e := &m.table[idx]
		for e.next != 0 {
			e = e.next
		}	
		e.next = &hashmapentry{key, val, 0}
	} else {
		m.table[idx] = hashmapentry{key, val, 0}
	}
}	

fn (m mut hashmap) get(key string) int {
	hash := int(b_fabs( key.hash() ))
	idx := hash % m.cap
	mut e := &m.table[idx]
	for e.next != 0 { // todo unsafe {
		if e.key == key {
			return e.val
		}	
		e = e.next
	}	
	return e.val
}

[inline] fn b_fabs(v int) f64 { return if v < 0 { -v } else { v } }