diff options
Diffstat (limited to 'theories/lmpmc_queue_proof.v')
| -rw-r--r-- | theories/lmpmc_queue_proof.v | 362 |
1 files changed, 362 insertions, 0 deletions
diff --git a/theories/lmpmc_queue_proof.v b/theories/lmpmc_queue_proof.v new file mode 100644 index 0000000..fa732cc --- /dev/null +++ b/theories/lmpmc_queue_proof.v | |||
| @@ -0,0 +1,362 @@ | |||
| 1 | From iris.program_logic Require Import atomic. | ||
| 2 | From iris.heap_lang Require Import notation proofmode. | ||
| 3 | From iris.algebra.lib Require Import excl_auth. | ||
| 4 | From iris.base_logic.lib Require Import invariants. | ||
| 5 | From iris.base_logic.lib Require Import invariants mono_nat mono_list. | ||
| 6 | From iris_named_props Require Import custom_syntax. | ||
| 7 | |||
| 8 | From lmpmc Require fin_queue_spec lmpmc_queue_spec. | ||
| 9 | From lmpmc Require Import upstream util. | ||
| 10 | |||
| 11 | Section lmpmc_queue. | ||
| 12 | Context {fq : fin_queue_spec.fin_queue_hl}. | ||
| 13 | |||
| 14 | Definition new : val := λ: <>, | ||
| 15 | let: "ℓ_q" := fq.(fin_queue_spec.new) #() in ("ℓ_q", "ℓ_q"). | ||
| 16 | |||
| 17 | Definition enqueue : val := (* passing arguments [ℓ_enq data] *) | ||
| 18 | fq.(fin_queue_spec.enqueue). | ||
| 19 | |||
| 20 | Definition try_dequeue : val := rec: "go" "ℓ_q" := | ||
| 21 | match: fq.(fin_queue_spec.try_dequeue) "ℓ_q" with | ||
| 22 | InjL "v" => | ||
| 23 | SOME "v" | ||
| 24 | | InjR "mℓ_nextq" => | ||
| 25 | match: "mℓ_nextq" with | ||
| 26 | NONE => NONE | ||
| 27 | | SOME "ℓ_nextq" => "go" "ℓ_nextq" | ||
| 28 | end | ||
| 29 | end. | ||
| 30 | |||
| 31 | Definition link : val := (* passing arguments [ℓ_enq1 ℓ_deq2] *) | ||
| 32 | fq.(fin_queue_spec.finalize). | ||
| 33 | |||
| 34 | Section proofs. | ||
| 35 | Context `{!heapGS Σ} {fqp : fin_queue_spec.fin_queue_iris Σ fq}. | ||
| 36 | |||
| 37 | Record node := Node { ℓ_node : loc; vs_node : list val }. | ||
| 38 | Add Printing Constructor node. | ||
| 39 | Definition linked_single_queue_repr (n : node) (mℓ_nextq : option loc) : iProp Σ := | ||
| 40 | fqp.(fin_queue_spec.queue_repr fq) n.(ℓ_node) n.(vs_node) (loc_to_val <$> mℓ_nextq). | ||
| 41 | |||
| 42 | Definition chain := list node. | ||
| 43 | Definition queue_repr ℓ_deq ℓ_enq (cvs : list val) : iProp Σ := | ||
| 44 | ∃ (c : chain), | ||
| 45 | ⌜length c > 0⌝ ∗ ⌜ℓ_node <$> head c = Some ℓ_deq⌝ ∗ | ||
| 46 | ⌜ℓ_node <$> last c = Some ℓ_enq⌝ ∗ ⌜cvs = c ≫= vs_node⌝ ∗ | ||
| 47 | [∗ list] i ↦ l ∈ c, linked_single_queue_repr l (ℓ_node <$> c !! S i). | ||
| 48 | |||
| 49 | #[global] Instance queue_repr_timeless ℓ_deq ℓ_enq cvs : Timeless (queue_repr ℓ_deq ℓ_enq cvs) := _. | ||
| 50 | |||
| 51 | Lemma new_spec : | ||
| 52 | {{{ True }}} | ||
| 53 | new #() | ||
| 54 | {{{ (ℓ_deq ℓ_enq : loc), RET (#ℓ_deq, #ℓ_enq); queue_repr ℓ_deq ℓ_enq [] }}}. | ||
| 55 | Proof. | ||
| 56 | iIntros (Φ _) "HΦ". iUnfold new. wp_pures. | ||
| 57 | wp_apply (fqp.(fin_queue_spec.new_spec fq) with "[//]"). | ||
| 58 | iIntros (ℓ) "H". wp_pures. iModIntro. iApply "HΦ". | ||
| 59 | unfold queue_repr. iExists [Node ℓ []]. | ||
| 60 | iFrame. iSimplifyEq. by iSplit; first (iPureIntro; lia). | ||
| 61 | Qed. | ||
| 62 | |||
| 63 | Lemma enqueue_spec (ℓ_enq : loc) (data : val) : | ||
| 64 | ⊢ <<{ ∀∀ ℓ_deq cvs, queue_repr ℓ_deq ℓ_enq cvs }>> | ||
| 65 | enqueue #ℓ_enq data @ ∅ | ||
| 66 | <<{ queue_repr ℓ_deq ℓ_enq (cvs ++ [data]) | RET #() }>>. | ||
| 67 | Proof. | ||
| 68 | iIntros "%Φ AU". iUnfold enqueue. | ||
| 69 | |||
| 70 | wp_bind (fin_queue_spec.enqueue _ _ _)%E. | ||
| 71 | awp_apply fqp.(fin_queue_spec.enqueue_spec fq). | ||
| 72 | rewrite /atomic_acc /=. | ||
| 73 | iMod "AU" as "(%ℓ_deq & %cvs & (%c & %Hclen & %Hhead & %Hlast & %Hcvs & Hqs) & Hclose)". | ||
| 74 | iModIntro. | ||
| 75 | |||
| 76 | destruct (last c) as [n_last|] eqn:Hlastn; last done. | ||
| 77 | iExists n_last.(vs_node). | ||
| 78 | |||
| 79 | apply last_Some in Hlastn as [c' ->]. | ||
| 80 | iDestruct (big_sepL_insert_acc _ _ (length c') with "Hqs") as "[Hnode Hrepr]". | ||
| 81 | { by rewrite lookup_app_r // Nat.sub_diag. } | ||
| 82 | iSimplifyEq. iUnfold linked_single_queue_repr in "Hnode". | ||
| 83 | |||
| 84 | rewrite lookup_app_r; last lia. | ||
| 85 | replace (S (length c') - length c') with 1 by lia. | ||
| 86 | simplify_eq/=. iFrame. | ||
| 87 | |||
| 88 | iSplit. | ||
| 89 | - iDestruct "Hclose" as "[Hclose _]". | ||
| 90 | iIntros "Hnode". | ||
| 91 | iDestruct ("Hrepr" with "[Hnode //]") as "Hrepr". | ||
| 92 | rewrite list_insert_id; last first. | ||
| 93 | { by rewrite lookup_app_r // Nat.sub_diag. } | ||
| 94 | iMod ("Hclose" with "[$Hrepr]") as "AU". | ||
| 95 | { by rewrite last_snoc. } | ||
| 96 | done. | ||
| 97 | - iDestruct "Hclose" as "[_ Hclose]". | ||
| 98 | iIntros "Hnode". | ||
| 99 | |||
| 100 | set n_last' := Node n_last.(ℓ_node) (n_last.(vs_node) ++ [data]). | ||
| 101 | set c := c' ++ [n_last']. | ||
| 102 | |||
| 103 | iDestruct ("Hrepr" with "[Hnode]") as "Hrepr". | ||
| 104 | { rewrite /linked_single_queue_repr /=. | ||
| 105 | replace (ℓ_node n_last) with n_last'.(ℓ_node) by done. | ||
| 106 | by replace (vs_node n_last ++ [data]) with n_last'.(vs_node). } | ||
| 107 | |||
| 108 | iMod ("Hclose" with "[Hrepr]") as "HΦ". | ||
| 109 | { unfold queue_repr. iExists c. repeat iSplit; try done. | ||
| 110 | - iPureIntro. rewrite length_app /=. lia. | ||
| 111 | - iPureIntro. rewrite /c. by destruct c'; simplify_eq/=. | ||
| 112 | - iPureIntro. by rewrite /c last_snoc. | ||
| 113 | - iPureIntro. by rewrite /c !bind_app /= !app_nil_r app_assoc. | ||
| 114 | - rewrite insert_app_r_alt // Nat.sub_diag /=. | ||
| 115 | iApply (big_sepL_mono with "Hrepr"). | ||
| 116 | { iIntros (i n Hi) "Hrepr". | ||
| 117 | rewrite -list_lookup_fmap fmap_app. | ||
| 118 | replace (ℓ_node <$> [n_last]) with (ℓ_node <$> [n_last']) by done. | ||
| 119 | by rewrite -fmap_app list_lookup_fmap. } } | ||
| 120 | |||
| 121 | iModIntro. iApply "HΦ". | ||
| 122 | Qed. | ||
| 123 | |||
| 124 | Lemma try_dequeue_spec (ℓ_deq : loc) : | ||
| 125 | ⊢ <<{ ∀∀ ℓ_enq cvs, queue_repr ℓ_deq ℓ_enq cvs }>> | ||
| 126 | try_dequeue #ℓ_deq @ ∅ | ||
| 127 | <<{ queue_repr ℓ_deq ℓ_enq (tail cvs) | RET (val_opt_hl (head cvs)) }>>. | ||
| 128 | Proof. | ||
| 129 | revert ℓ_deq. iLöb as "IH". iIntros (ℓ_deq Φ) "AU". wp_rec. | ||
| 130 | |||
| 131 | awp_apply (fqp.(fin_queue_spec.try_dequeue_spec fq)). | ||
| 132 | rewrite /atomic_acc /=. | ||
| 133 | iMod "AU" as "(%ℓ_enq & %cvs & (%c & %Hclen & %Hhead & %Hlast & %Hcvs & Hqs) & Hclose)". iModIntro. | ||
| 134 | |||
| 135 | destruct c as [|n_head c']; first done. | ||
| 136 | iDestruct (big_sepL_cons with "Hqs") as "[Hnode Hqs]". | ||
| 137 | simpl. destruct (c' !! 0) as [n_next|] eqn:Hnextq. | ||
| 138 | - iExists n_head.(vs_node), (Some #n_next.(ℓ_node)). iSplitL "Hnode"; last iSplit. | ||
| 139 | + simplify_eq/=. by rewrite /linked_single_queue_repr /=. | ||
| 140 | + simplify_eq/=. iIntros "Hnode". iDestruct "Hclose" as "[Hclose _]". | ||
| 141 | pose c := n_head :: c'. | ||
| 142 | iAssert (linked_single_queue_repr n_head (ℓ_node <$> c !! S 0)) with "[Hnode]" as "Hnode". | ||
| 143 | { by rewrite /linked_single_queue_repr /= Hnextq. } | ||
| 144 | iAssert ([∗ list] i↦n ∈ c', linked_single_queue_repr n (ℓ_node <$> c !! S (S i)))%I with "[Hqs //]" as "Hqs". | ||
| 145 | iAssert ([∗ list] i↦n ∈ c, linked_single_queue_repr n (ℓ_node <$> c !! S i))%I with "[Hnode Hqs]" as "Hqs". | ||
| 146 | { iApply big_sepL_cons. iFrame. } | ||
| 147 | iAssert (queue_repr n_head.(ℓ_node) ℓ_enq (vs_node n_head ++ c' ≫= vs_node)) with "[$Hqs //]" as "Hrepr". | ||
| 148 | by iMod ("Hclose" with "Hrepr") as "Hrepr". | ||
| 149 | + simplify_eq/=. iIntros "Hnode". | ||
| 150 | destruct n_head.(vs_node) as [|x vs_head'] eqn:Hvs_head. | ||
| 151 | * simplify_eq/=. iDestruct "Hclose" as "[Hclose _]". | ||
| 152 | |||
| 153 | iDestruct (fqp.(fin_queue_spec.queue_fin_obtain fq) with "Hnode") as "#Hfin". | ||
| 154 | |||
| 155 | pose c := n_head :: c'. | ||
| 156 | iAssert (linked_single_queue_repr n_head (ℓ_node <$> c !! S 0)) with "[Hnode]" as "Hnode". | ||
| 157 | { by rewrite /linked_single_queue_repr /= Hnextq Hvs_head /=. } | ||
| 158 | iAssert ([∗ list] i↦n ∈ c', linked_single_queue_repr n (ℓ_node <$> c !! S (S i)))%I with "[Hqs //]" as "Hqs". | ||
| 159 | iAssert ([∗ list] i↦n ∈ c, linked_single_queue_repr n (ℓ_node <$> c !! S i))%I with "[Hnode Hqs]" as "Hqs". | ||
| 160 | { iApply big_sepL_cons. iFrame. } | ||
| 161 | iAssert (queue_repr n_head.(ℓ_node) ℓ_enq (vs_node n_head ++ c' ≫= vs_node)) with "[$Hqs //]" as "Hrepr". | ||
| 162 | rewrite Hvs_head /=. iMod ("Hclose" with "Hrepr") as "AU". iModIntro. wp_pures. | ||
| 163 | clear c c' Hclen Hlast Hnextq Hvs_head. | ||
| 164 | |||
| 165 | awp_apply "IH". rewrite /atomic_acc /=. | ||
| 166 | iMod "AU" as "(%ℓ_enq' & %cvs' & (%c'' & _ & %Hhead' & %Hlast' & %Hcvs' & Hqs') & Hclose)". | ||
| 167 | destruct c'' as [|n_head' c'']; first done. | ||
| 168 | iDestruct (big_sepL_cons with "Hqs'") as "[Hq0 Hqs']". simplify_eq/=. | ||
| 169 | iEval (rewrite /linked_single_queue_repr /=) in "Hq0". | ||
| 170 | rewrite -Hhead'. | ||
| 171 | iDestruct (fqp.(fin_queue_spec.queue_fin_agree fq) with "Hfin Hq0") as %[Hhead Hc'']. | ||
| 172 | destruct (c'' !! 0) as [n_next'|] eqn:Hc''head; last done. simplify_eq/=. | ||
| 173 | rewrite -Hc''. clear Hhead' Hc'' n_next n_head. | ||
| 174 | assert (Hc''len : length c'' > 0). { by apply lookup_lt_Some in Hc''head. } | ||
| 175 | |||
| 176 | iAssert (queue_repr n_next'.(ℓ_node) ℓ_enq' (c'' ≫= vs_node)) with "[$Hqs']" as "Hrepr'". | ||
| 177 | { iPureIntro. repeat split; try done. | ||
| 178 | - by rewrite head_lookup Hc''head. | ||
| 179 | - enough (last c'' = last (n_head' :: c'')) as ->; first done. | ||
| 180 | destruct c''; first done. by rewrite last_cons_cons. } | ||
| 181 | |||
| 182 | iModIntro. iFrame. iSplit. | ||
| 183 | -- iIntros "(%d & %Hdlen & %Hdhead & %Hdlast & %Hdvs & Hrepr)". | ||
| 184 | rewrite Hhead /=. simplify_eq/=. | ||
| 185 | pose c := n_head' :: d. | ||
| 186 | iAssert (linked_single_queue_repr n_head' (ℓ_node <$> c !! S 0)) with "[Hq0]" as "Hq0". | ||
| 187 | { by rewrite /linked_single_queue_repr /= Hhead /= -head_lookup Hdhead /=. } | ||
| 188 | iAssert ([∗ list] i↦n ∈ c, linked_single_queue_repr n (ℓ_node <$> c !! S i))%I with "[Hq0 Hrepr]" as "Hrepr". | ||
| 189 | { iApply big_sepL_cons. iFrame. } | ||
| 190 | iAssert (queue_repr (ℓ_node n_head') ℓ_enq' (c'' ≫= vs_node)) with "[$Hrepr]" as "Hrepr". | ||
| 191 | { iPureIntro. repeat split; try done. | ||
| 192 | - unfold c. simpl. lia. | ||
| 193 | - unfold c. rewrite -Hdlast. by destruct d. | ||
| 194 | - unfold c. rewrite Hdvs. simplify_eq/=. | ||
| 195 | by rewrite Hhead. } | ||
| 196 | by iMod ("Hclose" with "Hrepr") as "AU". | ||
| 197 | -- iIntros "(%d & %Hdlen & %Hdhead & %Hdlast & %Hdvs & Hrepr)". | ||
| 198 | rewrite Hhead /=. simplify_eq/=. | ||
| 199 | pose c := n_head' :: d. | ||
| 200 | iAssert (linked_single_queue_repr n_head' (ℓ_node <$> c !! S 0)) with "[Hq0]" as "Hq0". | ||
| 201 | { by rewrite /linked_single_queue_repr /= Hhead /= -head_lookup Hdhead /=. } | ||
| 202 | iAssert ([∗ list] i↦n ∈ c, linked_single_queue_repr n (ℓ_node <$> c !! S i))%I with "[Hq0 Hrepr]" as "Hrepr". | ||
| 203 | { iApply big_sepL_cons. iFrame. } | ||
| 204 | iAssert (queue_repr (ℓ_node n_head') ℓ_enq' (tail (c'' ≫= vs_node))) with "[$Hrepr]" as "Hrepr". | ||
| 205 | { iPureIntro. repeat split; try done. | ||
| 206 | - unfold c. simpl. lia. | ||
| 207 | - unfold c. rewrite -Hdlast. by destruct d. | ||
| 208 | - unfold c. rewrite Hdvs. simplify_eq/=. | ||
| 209 | by rewrite Hhead. } | ||
| 210 | by iMod ("Hclose" with "Hrepr") as "AU". | ||
| 211 | * simplify_eq/=. iDestruct "Hclose" as "[_ Hclose]". | ||
| 212 | |||
| 213 | pose n_head' := Node (ℓ_node n_head) vs_head'. | ||
| 214 | pose c := n_head' :: c'. | ||
| 215 | |||
| 216 | iAssert (linked_single_queue_repr n_head' (ℓ_node <$> c !! S 0)) with "[Hnode]" as "Hnode". | ||
| 217 | { by rewrite /linked_single_queue_repr /= Hnextq /=. } | ||
| 218 | iAssert ([∗ list] i↦n ∈ c', linked_single_queue_repr n (ℓ_node <$> c !! S (S i)))%I with "[Hqs //]" as "Hqs". | ||
| 219 | iAssert ([∗ list] i↦n ∈ c, linked_single_queue_repr n (ℓ_node <$> c !! S i))%I with "[Hnode Hqs]" as "Hqs". | ||
| 220 | { iApply big_sepL_cons. iFrame. } | ||
| 221 | iAssert (queue_repr n_head.(ℓ_node) ℓ_enq (vs_node n_head' ++ c' ≫= vs_node)) with "[$Hqs]" as "Hrepr". | ||
| 222 | { iPureIntro. repeat split; try done. by destruct c'. } | ||
| 223 | |||
| 224 | iMod ("Hclose" with "Hrepr") as "Hrepr". | ||
| 225 | iModIntro. wp_pures. iApply "Hrepr". | ||
| 226 | - destruct c'; last done. simplify_eq/=. iClear "Hqs". | ||
| 227 | rewrite app_nil_r. clear Hclen. | ||
| 228 | iExists n_head.(vs_node), None. iSplitL "Hnode". | ||
| 229 | + by rewrite /linked_single_queue_repr /=. | ||
| 230 | + iSplit. | ||
| 231 | * iIntros "Hrepr". iDestruct "Hclose" as "[Hclose _]". | ||
| 232 | iMod ("Hclose" with "[Hrepr]") as "AU". | ||
| 233 | { iExists [n_head]. iFrame. | ||
| 234 | repeat iSplit; try done. | ||
| 235 | - iPureIntro. simpl. lia. | ||
| 236 | - simpl. by rewrite app_nil_r. } | ||
| 237 | done. | ||
| 238 | * iIntros "Hrepr". iDestruct "Hclose" as "[_ Hclose]". | ||
| 239 | set n_head' := Node n_head.(ℓ_node) (tail n_head.(vs_node)). | ||
| 240 | iMod ("Hclose" with "[Hrepr]") as "HΦ". | ||
| 241 | { iExists [n_head']. iFrame. | ||
| 242 | repeat iSplit; try done. | ||
| 243 | - iPureIntro. simpl. lia. | ||
| 244 | - simpl. by rewrite app_nil_r. } | ||
| 245 | destruct n_head.(vs_node) as [|v vs']; | ||
| 246 | iModIntro; wp_pures; iApply "HΦ". | ||
| 247 | Qed. | ||
| 248 | |||
| 249 | (** Linking two queues: | ||
| 250 | * _______________ _______________ | ||
| 251 | * / Q1 \ / Q2 \ | ||
| 252 | * ℓ_deq1 ... ℓ_enq1 <> ℓ_deq2 ... ℓ_enq2 | ||
| 253 | * \ \ link op args / / | ||
| 254 | * \ \____________/ / | ||
| 255 | * \ Q1 <> Q2 / | ||
| 256 | * \______________________________/ | ||
| 257 | *) | ||
| 258 | Lemma link_spec (ℓ_enq1 ℓ_deq2 : loc) : | ||
| 259 | ⊢ <<{ ∀∀ (b : bool) ℓ_deq1 ℓ_enq2 cvs1 cvs2, queue_repr ℓ_deq1 ℓ_enq1 cvs1 ∗ | ||
| 260 | if b then queue_repr ℓ_deq2 ℓ_enq2 cvs2 else ⌜ℓ_deq1 = ℓ_deq2 ∧ ℓ_enq1 = ℓ_enq2⌝ }>> | ||
| 261 | link #ℓ_enq1 #ℓ_deq2 @ ∅ | ||
| 262 | <<{ if b then queue_repr ℓ_deq1 ℓ_enq2 (cvs1 ++ cvs2) else True | RET #() }>>. | ||
| 263 | Proof. | ||
| 264 | iIntros "%Φ AU". iUnfold link. | ||
| 265 | |||
| 266 | wp_bind (fin_queue_spec.finalize _ _ _)%E. | ||
| 267 | awp_apply fqp.(fin_queue_spec.finalize_spec fq). | ||
| 268 | rewrite /atomic_acc /=. | ||
| 269 | iMod "AU" as (b ℓ_deq1 ℓ_enq2 cvs1 cvs2) "[[(%c1 & %Hclen1 & %Hhead1 & %Hlast1 & %Hcvs1 & Hqs1) Hqs2] Hclose]". | ||
| 270 | iModIntro. | ||
| 271 | |||
| 272 | destruct (last c1) as [n_last1|] eqn:Hlastn1; last done. | ||
| 273 | iExists n_last1.(vs_node). | ||
| 274 | |||
| 275 | apply last_Some in Hlastn1 as [c1' ->]. | ||
| 276 | iDestruct (big_sepL_app with "Hqs1") as "[Hqs1 Hnode]". | ||
| 277 | iSimplifyEq. iDestruct "Hnode" as "[Hnode _]". | ||
| 278 | rewrite Nat.add_0_r. | ||
| 279 | |||
| 280 | rewrite lookup_ge_None_2 /=; last first. | ||
| 281 | { rewrite length_app /=. lia. } | ||
| 282 | iUnfold linked_single_queue_repr in "Hnode". | ||
| 283 | iSimplifyEq. iFrame. | ||
| 284 | |||
| 285 | iSplit. | ||
| 286 | - iDestruct "Hclose" as "[Hclose _]". | ||
| 287 | iIntros "Hnode". | ||
| 288 | |||
| 289 | iAssert (linked_single_queue_repr n_last1 (ℓ_node <$> (c1' ++ [n_last1]) !! S (length c1'))) with "[Hnode]" as "Hnode". | ||
| 290 | { rewrite /linked_single_queue_repr !lookup_app_r; last lia. | ||
| 291 | by assert (S (length c1') - length c1' = 1) as -> by lia. } | ||
| 292 | |||
| 293 | iDestruct (big_sepL_snoc with "[$Hqs1 $Hnode]") as "Hqs1'". | ||
| 294 | |||
| 295 | iPoseProof ("Hclose" with "[$Hqs1' $Hqs2]") as "Hqs". | ||
| 296 | { iPureIntro. repeat split; try done. by rewrite last_app. } | ||
| 297 | done. | ||
| 298 | |||
| 299 | - iDestruct "Hclose" as "[_ Hclose]". | ||
| 300 | iIntros "Hnode". | ||
| 301 | |||
| 302 | destruct b; last by iApply "Hclose". | ||
| 303 | iDestruct "Hqs2" as "(%c2 & %Hclen2 & %Hhead2 & %Hlast2 & %Hcvs2 & Hqs2)". | ||
| 304 | |||
| 305 | pose c := (c1' ++ [n_last1]) ++ c2. | ||
| 306 | |||
| 307 | iAssert (linked_single_queue_repr n_last1 (ℓ_node <$> c !! S (length c1'))) with "[Hnode]" as "Hnode". | ||
| 308 | { rewrite /linked_single_queue_repr /c !lookup_app_r; try (rewrite length_app /=; lia). | ||
| 309 | rewrite length_app /=. assert (S (length c1') - (length c1' + 1) = 0) as -> by lia. | ||
| 310 | rewrite -head_lookup Hhead2 //=. } | ||
| 311 | |||
| 312 | iDestruct (big_sepL_mono with "Hqs1") as "Hqs1". | ||
| 313 | { iIntros (i l Hi) "Hrepr". | ||
| 314 | iAssert (linked_single_queue_repr l (ℓ_node <$> c !! S i))%I with "[Hrepr]" as "Hrepr". | ||
| 315 | { rewrite /c lookup_app_l // length_app /=. apply lookup_lt_Some in Hi. lia. } | ||
| 316 | iExact "Hrepr". } | ||
| 317 | |||
| 318 | iDestruct (big_sepL_snoc with "[$Hqs1 $Hnode]") as "Hqs1'". | ||
| 319 | |||
| 320 | iDestruct (big_sepL_mono with "Hqs2") as "Hqs2". | ||
| 321 | { iIntros (i l Hi) "Hrepr". | ||
| 322 | iAssert (linked_single_queue_repr l (ℓ_node <$> c !! S (length (c1' ++ [n_last1]) + i)))%I with "[Hrepr]" as "Hrepr". | ||
| 323 | { rewrite /c length_app /= lookup_app_r length_app /=; last lia. | ||
| 324 | by assert (S i = S (length c1' + 1 + i) - (length c1' + 1)) as -> by lia. } | ||
| 325 | iExact "Hrepr". } | ||
| 326 | iSimplifyEq. | ||
| 327 | |||
| 328 | iDestruct (big_sepL_app with "[$Hqs1' $Hqs2]") as "Hqs". fold c. | ||
| 329 | rewrite -bind_app -/c. | ||
| 330 | iMod ("Hclose" with "[Hqs]") as "HΦ". | ||
| 331 | { iFrame. iPureIntro. repeat split; try done. | ||
| 332 | - rewrite /c !length_app /=. lia. | ||
| 333 | - rewrite /c head_app. case_match; last done. congruence. | ||
| 334 | - rewrite /c last_app. case_match; last done. congruence. } | ||
| 335 | iModIntro. iApply "HΦ". | ||
| 336 | Qed. | ||
| 337 | |||
| 338 | End proofs. | ||
| 339 | |||
| 340 | End lmpmc_queue. | ||
| 341 | |||
| 342 | Definition lmpmc_queue_hl (fq : fin_queue_spec.fin_queue_hl) : lmpmc_queue_spec.lmpmc_queue_hl. | ||
| 343 | Proof. | ||
| 344 | by refine {| lmpmc_queue_spec.new := new; | ||
| 345 | lmpmc_queue_spec.enqueue := enqueue; | ||
| 346 | lmpmc_queue_spec.try_dequeue := try_dequeue; | ||
| 347 | lmpmc_queue_spec.link := link |}. | ||
| 348 | Defined. | ||
| 349 | |||
| 350 | Definition lmpmc_queue_iris `{!heapGS Σ} | ||
| 351 | (fq : fin_queue_spec.fin_queue_hl) | ||
| 352 | (fqp : fin_queue_spec.fin_queue_iris Σ fq) : lmpmc_queue_spec.lmpmc_queue_iris Σ (lmpmc_queue_hl fq). | ||
| 353 | Proof. | ||
| 354 | by refine (lmpmc_queue_spec.LmpmcQueueIris _ _ | ||
| 355 | (lmpmc_queue_hl fq) _ _ | ||
| 356 | new_spec | ||
| 357 | enqueue_spec | ||
| 358 | try_dequeue_spec | ||
| 359 | link_spec). | ||
| 360 | Defined. | ||
| 361 | |||
| 362 | #[global] Typeclasses Opaque queue_repr. | ||