Theory LLVM_DS_Circ_List

section Circular Singly Linked Lists
theory LLVM_DS_Circ_List
imports LLVM_DS_List_Seg
begin

text 
  Example of circular lists, with efficient append, prepend, pop, and rotate
  operations.
  
  TODO: Add delete operation,. e.g. by iterating pop


subsection Datatype Definition

type_synonym 'a cs_list = "'a node ptr"

definition "cs_list_assn  mk_assn (λxs p. lseg xs p p ** (xs=[]  p=null))"

lemma cs_list_assn_simps:
  "cs_list_assn xs null = (xs=[])"
  "cs_list_assn [] p = (p=null)"
  unfolding cs_list_assn_def 
  by (auto simp: sep_algebra_simps)


subsection Operations
subsubsection Allocate Empty List
definition cs_empty :: "'a::llvm_rep cs_list llM" where [llvm_code, llvm_inline]:
  "cs_empty  Mreturn null"

lemma cs_empty_rule: "llvm_htriple  cs_empty (λr. cs_list_assn [] r)"
  unfolding cs_empty_def cs_list_assn_def
  by vcg

subsubsection Prepend Element

definition cs_prepend :: "'a::llvm_rep  'a cs_list  'a cs_list llM" where [llvm_code]:
  "cs_prepend x p  
    if p=null then doM {
      p  ll_balloc;
      ll_store (Node x p) p;
      Mreturn p
    } else doM {
      n  ll_load p;
      q  ll_ref (Node (node.val n) (node.next n));
      ll_store (Node x q) p;
      Mreturn p
    }"

lemma cs_prepend_rule: 
  "llvm_htriple (cs_list_assn xs p) (cs_prepend x p) (λr. cs_list_assn (x#xs) r)"
  unfolding cs_prepend_def cs_list_assn_def
  apply (cases "xs"; simp)
  apply vcg
  done

subsubsection Append Element
definition cs_append :: "'a::llvm_rep  'a cs_list  'a cs_list llM" where [llvm_code]:
  "cs_append x p  doM {
    if p=null then doM {
      p  ll_balloc;
      ll_store (Node x p) p;
      Mreturn p
    } else doM {
      n  ll_load p;
      q  ll_ref (Node (node.val n) (node.next n));
      ll_store (Node x q) p;
      Mreturn q
    }
  }"

lemma cs_append_rule: 
  "llvm_htriple (cs_list_assn xs p) (cs_append x p) (λr. cs_list_assn (xs@[x]) r)"
  unfolding cs_append_def cs_list_assn_def
  apply (cases "xs"; simp add: lseg_append)
  apply vcg
  done

subsubsection Pop First Element

definition cs_pop :: "'a::llvm_rep cs_list  ('a×'a cs_list) llM" where [llvm_code]:
  "cs_pop p  doM {
    n1  ll_load p;
    let p2 = node.next n1;
    tmp  ll_ptrcmp_eq p2 p;
    if to_bool tmp then doM {
      ll_free p;
      Mreturn (node.val n1,null) ― ‹Singleton list becomes empty list
    } else doM {
      n2  ll_load p2;
      ll_store n2 p;
      ll_free p2;
      Mreturn (node.val n1,p)
    }
  }"

  
lemma ll_bpto_not_same1: 
  "(ll_bpto x p ∧* ll_bpto y p) = sep_false"  
  apply (auto simp: ll_bpto_def sep_algebra_simps ll_pto_not_same)
  by (simp add: ll_pto_not_same sep.mult.left_commute sep.mult_commute)

lemma ll_bpto_not_same2: 
  "(ll_bpto x p ∧* ll_bpto y p ** F) = sep_false"  
  apply (auto simp: ll_bpto_def sep_algebra_simps ll_pto_not_same)
  by (simp add: ll_pto_not_same sep.mult.left_commute sep.mult_commute)

lemmas ll_bpto_not_same = ll_bpto_not_same1 ll_bpto_not_same2  
    
context  
begin
  interpretation llvm_prim_ctrl_setup .
  interpretation llvm_prim_arith_setup .
  
lemma cs_pop_rule: 
  "llvm_htriple (cs_list_assn (x#xs) p) (cs_pop p) (λ(y,p'). cs_list_assn xs p' ** (y=x))"
  unfolding cs_list_assn_def cs_pop_def
  apply (cases xs; simp)
  supply [simp] = ll_bpto_not_same
  apply vcg
  done

end
  
subsubsection Rotate

definition cs_rotate :: "'a::llvm_rep cs_list  'a cs_list llM" where [llvm_code]:
  "cs_rotate p  if p=null then Mreturn null else doM {
    n  ll_load p;
    Mreturn (node.next n)
  }"

  
lemma list01_cases:
  obtains (Nil) "xs=[]" | (Sng) x where "xs=[x]" | (Long) x y xs' where "xs=x#y#xs'"
  by (rule remdups_adj.cases)
  
  
  
lemma cs_rotate_rule: 
  "llvm_htriple (cs_list_assn xs p) (cs_rotate p) (λr. cs_list_assn (rotate1 xs) r)"
  unfolding cs_list_assn_def cs_rotate_def
  apply (cases xs rule: list01_cases; simp add: lseg_append)
  apply vcg
  done

subsection Test
definition [llvm_code]: "test  doM {
  l  cs_empty;
  l  cs_append 1 l;
  l  cs_append 2 l;
  l  cs_append 3 l;
  l  cs_prepend 4 l;
  l  cs_rotate l;
  (v1,l)cs_pop l;
  (v2,l)cs_pop l;
  (v3,l)cs_pop l;
  (v4,l)cs_pop l;
  Mreturn (v1,v2,v3,v4)
}"

(* TODO: Move! *)

export_llvm 
  "cs_empty :: 64 word cs_list llM"
  "cs_prepend :: 64 word  _"
  "cs_append :: 64 word  _"
  "cs_pop :: 64 word cs_list  _"

export_llvm "test :: (64 word × _) llM"

end