#!/usr/bin/env joker
(ns benchmark-vector
  "Benchmark for vector construction optimizations.

   Tests:
   - NewVectorFrom: via (vector ...) and (apply vector ...)
   - NewVectorFromSeq: via (vec seq) for counted and non-counted seqs
   - NewArrayVectorFrom: via map entry creation"
  (:require [joker.time :as t]))

(defn benchmark
  "Run f iterations times and return elapsed time in milliseconds."
  [iterations f]
  (let [start (t/now)]
    (dotimes [_ iterations]
      (f))
    (/ (t/since start) 1000000.0)))

(defn run-benchmark
  "Run a benchmark and print results."
  [name iterations f]
  (let [elapsed (benchmark iterations f)
        per-op (/ (* elapsed 1000) iterations)] ; microseconds per operation
    (printf "  %-45s %8.2f ms  (%6.3f us/op)\n" name elapsed per-op)))

(defn separator []
  (println (apply str (repeat 75 "-"))))

;; =============================================================================
;; NewVectorFrom benchmarks (via `vector` function)
;; =============================================================================

(defn bench-vector-empty []
  (vector))

(defn bench-vector-1 []
  (vector 1))

(defn bench-vector-10 []
  (vector 1 2 3 4 5 6 7 8 9 10))

(defn bench-vector-32 []
  (apply vector (range 32)))

(defn bench-vector-33 []
  (apply vector (range 33)))

(defn bench-vector-100 []
  (apply vector (range 100)))

(defn bench-vector-1000 []
  (apply vector (range 1000)))

;; =============================================================================
;; NewVectorFromSeq benchmarks (via `vec` function)
;; =============================================================================

;; From list (Counted)
(def list-32 (apply list (range 32)))
(def list-100 (apply list (range 100)))
(def list-1000 (apply list (range 1000)))

(defn bench-vec-from-list-32 []
  (vec list-32))

(defn bench-vec-from-list-100 []
  (vec list-100))

(defn bench-vec-from-list-1000 []
  (vec list-1000))

;; From range (becomes ArraySeq which is Counted)
(defn bench-vec-from-range-32 []
  (vec (range 32)))

(defn bench-vec-from-range-100 []
  (vec (range 100)))

(defn bench-vec-from-range-1000 []
  (vec (range 1000)))

;; From lazy seq (not Counted - exercises fallback path)
(defn bench-vec-from-lazy-32 []
  (vec (map identity (range 32))))

(defn bench-vec-from-lazy-100 []
  (vec (map identity (range 100))))

(defn bench-vec-from-lazy-1000 []
  (vec (map identity (range 1000))))

;; From vector seq
(def vec-100 (vec (range 100)))
(def vec-1000 (vec (range 1000)))

(defn bench-vec-from-vecseq-100 []
  (vec (seq vec-100)))

(defn bench-vec-from-vecseq-1000 []
  (vec (seq vec-1000)))

;; =============================================================================
;; NewArrayVectorFrom benchmarks (via map operations)
;; =============================================================================

(def small-map {:a 1 :b 2 :c 3 :d 4})
(def medium-map (zipmap (range 8) (range 8)))

(defn bench-map-entries-small []
  (doall (seq small-map)))

(defn bench-map-entries-medium []
  (doall (seq medium-map)))

(defn bench-map-first-entry []
  (first {:a 1}))

;; =============================================================================
;; Main
;; =============================================================================

(defn -main []
  (println "\nVector Construction Benchmark")
  (println "==============================\n")

  (let [iterations 100000
        large-iterations 10000]

    (println "NewVectorFrom (via `vector` function)")
    (separator)
    (run-benchmark "(vector)" iterations bench-vector-empty)
    (run-benchmark "(vector 1)" iterations bench-vector-1)
    (run-benchmark "(vector 1 2 ... 10)" iterations bench-vector-10)
    (run-benchmark "(apply vector (range 32))" iterations bench-vector-32)
    (run-benchmark "(apply vector (range 33))" iterations bench-vector-33)
    (run-benchmark "(apply vector (range 100))" iterations bench-vector-100)
    (run-benchmark "(apply vector (range 1000))" large-iterations bench-vector-1000)
    (println)

    (println "NewVectorFromSeq - Counted seqs (optimized path)")
    (separator)
    (run-benchmark "(vec list-32)" iterations bench-vec-from-list-32)
    (run-benchmark "(vec list-100)" iterations bench-vec-from-list-100)
    (run-benchmark "(vec list-1000)" large-iterations bench-vec-from-list-1000)
    (run-benchmark "(vec (range 32))" iterations bench-vec-from-range-32)
    (run-benchmark "(vec (range 100))" iterations bench-vec-from-range-100)
    (run-benchmark "(vec (range 1000))" large-iterations bench-vec-from-range-1000)
    (run-benchmark "(vec (seq vec-100))" iterations bench-vec-from-vecseq-100)
    (run-benchmark "(vec (seq vec-1000))" large-iterations bench-vec-from-vecseq-1000)
    (println)

    (println "NewVectorFromSeq - Non-Counted seqs (fallback path)")
    (separator)
    (run-benchmark "(vec (map identity (range 32)))" iterations bench-vec-from-lazy-32)
    (run-benchmark "(vec (map identity (range 100)))" iterations bench-vec-from-lazy-100)
    (run-benchmark "(vec (map identity (range 1000)))" large-iterations bench-vec-from-lazy-1000)
    (println)

    (println "NewArrayVectorFrom (via map entries)")
    (separator)
    (run-benchmark "(seq {:a 1 :b 2 :c 3 :d 4})" iterations bench-map-entries-small)
    (run-benchmark "(seq (zipmap (range 8) (range 8)))" iterations bench-map-entries-medium)
    (run-benchmark "(first {:a 1})" iterations bench-map-first-entry)
    (println)))

(-main)
