/-
Copyright (c) 2018 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import Init.Data.Array.Basic

@[inline] def Array.insertionSort (a : Array α) (lt : α → α → Bool) : Array α :=
  traverse a 0 a.size
where
  @[specialize] traverse (a : Array α) (i : Nat) (fuel : Nat) : Array α :=
    match fuel with
    | 0      => a
    | fuel+1 =>
      if h : i < a.size then
        traverse (swapLoop a i h) (i+1) fuel
      else
        a
  @[specialize] swapLoop (a : Array α) (j : Nat) (h : j < a.size) : Array α :=
    match (generalizing := false) he:j with -- using `generalizing` because we don't want to refine the type of `h`
    | 0    => a
    | j'+1 =>
      have h' : j' < a.size := by subst j; exact Nat.lt_trans (Nat.lt_succ_self _) h
      if lt (a.get ⟨j, h⟩) (a.get ⟨j', h'⟩) then
        swapLoop (a.swap ⟨j, h⟩ ⟨j', h'⟩) j' (by rw [size_swap]; assumption done)
      else
        a
