# Semana 7: tablas hash. Se usa dentro del entorno del curso.
#
#   make           compila los programas de la clase en build/
#   make lab       compila el laboratorio en build/lab/
#   make test      corre las pruebas de los ejemplos y de los apuntes
#   make test-map  prueba solo HashMap (pasos 1 y 2 del laboratorio)
#   make test-calc prueba el evaluador (paso 3)
#   make test-hash prueba las funciones hash y chain_lengths (paso 4)
#   make test-lab  prueba todo su laboratorio; falla hasta que lo terminen
#   make report    tabla del paso 4 con el diccionario real, con -O2 y sin sanitizers
#   make clean     borra lo generado
#
# Los programas de errors/ tienen errores a propósito. No se compilan con make:
# los compilan las pruebas, y ustedes, con los comandos de los apuntes.

CXX = g++
CXXFLAGS = -Wall -Wextra -std=c++20 -g -fsanitize=address,undefined
BENCHFLAGS = -Wall -Wextra -std=c++20 -O2
DATA ?= ../../data
LAB_DIR ?= lab
BUILD = build
PROGRAMS = hash_demo fnv_trace chain_trace growth_count library_demo test_structures
BENCHES = first_collision hash_compare load_experiment naive_copy flood lookup_bench
COMMON_HEADERS = hash_functions.h chain_table.h word_file.h tracked.h bench.h
LAB_HEADERS = $(LAB_DIR)/hash_map.h $(LAB_DIR)/chain_lengths.h $(LAB_DIR)/var_table.h
OUT = $(BUILD)/$(LAB_DIR)
TEST_HEADERS = lab/tests/map_suite.h lab/tests/alloc_counter.h lab/tests/tracked.h

.PHONY: all lab test test-map test-calc test-hash test-lab report clean

all: $(PROGRAMS:%=$(BUILD)/%) $(BENCHES:%=$(BUILD)/%)

$(PROGRAMS:%=$(BUILD)/%): $(BUILD)/%: %.cpp $(COMMON_HEADERS) | $(BUILD)
	$(CXX) $(CXXFLAGS) $< -o $@

# Las mediciones van con -O2 y sin sanitizers.
$(BENCHES:%=$(BUILD)/%): $(BUILD)/%: %.cpp $(COMMON_HEADERS) | $(BUILD)
	$(CXX) $(BENCHFLAGS) $< -o $@

# LAB_DIR va primero: así las pruebas y los programas dados toman los archivos de esa carpeta.
$(OUT)/map_tests: lab/tests/map_tests.cpp $(TEST_HEADERS) $(LAB_HEADERS) | $(OUT)
	$(CXX) $(CXXFLAGS) -I$(LAB_DIR) -Ilab/tests $< -o $@

$(OUT)/hash_tests: lab/tests/hash_tests.cpp $(LAB_HEADERS) | $(OUT)
	$(CXX) $(CXXFLAGS) -fsigned-char -I$(LAB_DIR) $< -o $@

$(OUT)/calc: lab/given/calc.cpp lab/given/evaluator.h $(LAB_HEADERS) | $(OUT)
	$(CXX) $(CXXFLAGS) -I$(LAB_DIR) $< -o $@

$(OUT)/chain_report: lab/given/chain_report.cpp $(LAB_HEADERS) | $(OUT)
	$(CXX) $(CXXFLAGS) -I$(LAB_DIR) $< -o $@

$(OUT)/chain_report_fast: lab/given/chain_report.cpp $(LAB_HEADERS) | $(OUT)
	$(CXX) $(BENCHFLAGS) -I$(LAB_DIR) $< -o $@

$(BUILD) $(OUT):
	mkdir -p $@

lab: $(OUT)/map_tests $(OUT)/hash_tests $(OUT)/calc $(OUT)/chain_report $(OUT)/chain_report_fast

# Si existe solution/, también se comprueba la solución del laboratorio.
test: all
	@if [ -d solution ]; then $(MAKE) --no-print-directory LAB_DIR=solution lab; fi
	DATA=$(DATA) python3 -m unittest discover -p 'test_*.py'

test-map: lab
	DATA=$(DATA) LAB_DIR=$(LAB_DIR) python3 -m unittest -v test_lab.TestMap

test-calc: lab
	DATA=$(DATA) LAB_DIR=$(LAB_DIR) python3 -m unittest -v test_lab.TestCalc

test-hash: lab
	DATA=$(DATA) LAB_DIR=$(LAB_DIR) python3 -m unittest -v test_lab.TestHash

test-lab: all lab
	DATA=$(DATA) LAB_DIR=$(LAB_DIR) python3 -m unittest -v test_lab

report: $(OUT)/chain_report_fast
	$< $(DATA)/palabras.txt

clean:
	rm -rf $(BUILD) __pycache__
