summaryrefslogtreecommitdiffstats
path: root/theories/fin_queue_proof.v
diff options
context:
space:
mode:
Diffstat (limited to 'theories/fin_queue_proof.v')
-rw-r--r--theories/fin_queue_proof.v932
1 files changed, 932 insertions, 0 deletions
diff --git a/theories/fin_queue_proof.v b/theories/fin_queue_proof.v
new file mode 100644
index 0000000..64646ae
--- /dev/null
+++ b/theories/fin_queue_proof.v
@@ -0,0 +1,932 @@
1From iris.program_logic Require Import atomic.
2From iris.heap_lang Require Import notation proofmode.
3From iris.algebra.lib Require Import excl_auth.
4From iris.base_logic.lib Require Import invariants.
5From iris.base_logic.lib Require Import invariants mono_nat mono_list.
6From iris_named_props Require Import custom_syntax.
7
8From lmpmc Require Import fin_queue_spec upstream util.
9
10Definition new_node : val := λ: "data" "final",
11 let: "ℓ_node" := AllocN #3 #() in
12 "ℓ_node" <- "data";;
13 "ℓ_node" +ₗ #1 <- NONE;;
14 "ℓ_node" +ₗ #2 <- "final";;
15 "ℓ_node".
16
17Definition new : val := λ: <>,
18 let: "ℓ_node" := new_node #() #false in
19 AllocN #2 "ℓ_node".
20
21Definition set_tail : val := rec: "go" "ℓ_q" "ℓ_node" :=
22 let: "ℓ_tail" := !("ℓ_q" +ₗ #1) in
23 match: !("ℓ_tail" +ₗ #1) with
24 NONE =>
25 if: CAS ("ℓ_tail" +ₗ #1) NONE (SOME "ℓ_node") then
26 #()
27 else
28 "go" "ℓ_q" "ℓ_node"
29 | SOME "ℓ_next" =>
30 CAS ("ℓ_q" +ₗ #1) "ℓ_tail" "ℓ_next";;
31 "go" "ℓ_q" "ℓ_node"
32 end.
33
34Definition enqueue : val := λ: "ℓ_q" "data",
35 set_tail "ℓ_q" (new_node "data" #false).
36
37Definition finalize : val := λ: "ℓ_q" "data",
38 set_tail "ℓ_q" (new_node "data" #true).
39
40Definition try_dequeue : val := rec: "go" "ℓ_q" :=
41 let: "ℓ_head" := !"ℓ_q" in
42 match: !("ℓ_head" +ₗ #1) with
43 NONE => InjR NONE
44 | SOME "ℓ_next" =>
45 if: !("ℓ_next" +ₗ #2) then
46 (* The next node is the final node. We refuse to dequeue and
47 return the data of the final node. *)
48 InjR (SOME !"ℓ_next")
49 else (* [ℓ_next] node type = normal *)
50 let: "v" := !"ℓ_next" in
51 if: CAS "ℓ_q" "ℓ_head" "ℓ_next" then
52 InjL "v"
53 else
54 "go" "ℓ_q"
55 end.
56
57Class fin_queueG Σ := FinQueueG
58 { fin_queue_mono_natG :: mono_natG Σ;
59 fin_queue_mono_listG :: mono_listG (prodO locO valO) Σ; }.
60
61Definition fin_queueΣ : gFunctors :=
62 #[ mono_natΣ; mono_listΣ (prodO locO valO) ].
63
64#[global] Instance subG_fin_queueΣ {Σ} : subG fin_queueΣ Σ → fin_queueG Σ.
65Proof. solve_inG. Qed.
66
67Section fin_queue.
68 Context `{!heapGS Σ, !fin_queueG Σ}.
69
70 Record gstate :=
71 { γ_hist : gname;
72 γ_hpos : gname; }.
73 Definition gstate_to_pair (γ : gstate) :=
74 (γ.(γ_hist), γ.(γ_hpos)).
75 Definition gstate_of_pair '(γ_hist, γ_hpos) :=
76 {| γ_hist := γ_hist; γ_hpos := γ_hpos |}.
77 Instance gstate_eq_dec : EqDecision gstate := ltac:(solve_decision).
78 Instance gstate_countable : Countable gstate.
79 Proof.
80 refine {| encode := encode ∘ gstate_to_pair;
81 decode := fmap gstate_of_pair ∘ decode; |}.
82 intros []. by rewrite /= decode_encode.
83 Qed.
84
85 Variant node_next :=
86 | Normal (mℓ_next : option loc)
87 | Final.
88 Instance node_next_eq_dec : EqDecision node_next.
89 Proof. solve_decision. Defined.
90 Definition node_final_hl (n : node_next) := #(bool_decide (n = Final)).
91 Definition node_next_hl (n : node_next) :=
92 match n with
93 | Normal mℓ_next => loc_opt_hl mℓ_next
94 | Final => NONEV
95 end.
96
97 Definition node_repr (ℓ : loc) (data : val) (n : node_next) : iProp Σ :=
98 ("Hndata" ∷ ℓ ↦□ data) ∗
99 ("Hnnext" ∷ (ℓ +ₗ 1) ↦ node_next_hl n) ∗
100 ("Hnfinal" ∷ (ℓ +ₗ 2) ↦□ #(bool_decide (n = Final))).
101
102 Definition loc_at (hist : list (loc * val)) i :=
103 hist.*1 !! i.
104 Definition val_at (hist : list (loc * val)) i :=
105 hist.*2 !! i.
106
107 Lemma loc_at_prefix xs xs' i ℓ :
108 loc_at xs i = Some ℓ → xs `prefix_of` xs' → loc_at xs' i = Some ℓ.
109 Proof.
110 unfold loc_at. intros Hxs Hpre.
111 eapply prefix_lookup_Some; first exact Hxs.
112 by apply prefix_of_fmap.
113 Qed.
114
115 Lemma val_at_prefix xs xs' i ℓ :
116 val_at xs i = Some ℓ → xs `prefix_of` xs' → val_at xs' i = Some ℓ.
117 Proof.
118 unfold val_at. intros Hxs Hpre.
119 eapply prefix_lookup_Some; first exact Hxs.
120 by apply prefix_of_fmap.
121 Qed.
122
123 Lemma loc_at_val_at_Some xs i ℓ :
124 loc_at xs i = Some ℓ → ∃ v, val_at xs i = Some v.
125 Proof.
126 unfold loc_at, val_at. rewrite [xs.*2 !! i]list_lookup_fmap.
127 intros [[ℓ' v] [-> ->]]%list_lookup_fmap_Some_1. by exists v.
128 Qed.
129
130 Lemma loc_at_val_at_combine {hist i ℓ v} :
131 loc_at hist i = Some ℓ →
132 val_at hist i = Some v →
133 hist !! i = Some (ℓ, v).
134 Proof.
135 unfold loc_at, val_at. intros Hloc Hval.
136 rewrite list_lookup_fmap in Hloc.
137 rewrite list_lookup_fmap in Hval.
138 destruct (hist !! i) as [[ℓ' v']|]; last done.
139 simpl in *. congruence.
140 Qed.
141
142 Lemma loc_at_Some_length hist i ℓ :
143 loc_at hist i = Some ℓ → i < length hist.
144 Proof.
145 intros Hloc%lookup_lt_Some.
146 by rewrite length_fmap in Hloc.
147 Qed.
148
149 Lemma loc_at_drop hist n i ℓ :
150 loc_at hist (n + i) = Some ℓ →
151 loc_at (drop n hist) i = Some ℓ.
152 Proof.
153 unfold loc_at. intros Hloc.
154 by rewrite list_lookup_fmap lookup_drop -list_lookup_fmap.
155 Qed.
156
157 Lemma val_at_drop hist n i ℓ :
158 val_at hist (n + i) = Some ℓ →
159 val_at (drop n hist) i = Some ℓ.
160 Proof.
161 unfold val_at. intros Hval.
162 by rewrite list_lookup_fmap lookup_drop -list_lookup_fmap.
163 Qed.
164
165 Definition next_from (hist : list (loc * val)) fin i :=
166 if fin && bool_decide (S i = length hist) then Final else Normal (loc_at hist (S i)).
167
168 Definition next_from_normal hist fin i v :
169 next_from hist fin i = Normal v →
170 (fin = false ∨ S i ≠ length hist) ∧ loc_at hist (S i) = v.
171 Proof.
172 rewrite /next_from. intros H.
173 destruct fin, (decide (S i = length hist)).
174 - rewrite bool_decide_true //= in H.
175 - rewrite bool_decide_false //= in H.
176 injection H as <-. split; last done. by right.
177 - injection H as <-. split; last done. by left.
178 - injection H as <-. split; last done. by left.
179 Qed.
180
181 Lemma next_from_S ℓv ℓvs fin n :
182 next_from (ℓv :: ℓvs) fin (S n) = next_from ℓvs fin n.
183 Proof.
184 rewrite /next_from /loc_at list_lookup_fmap /= -list_lookup_fmap.
185 erewrite bool_decide_ext; first done. lia.
186 Qed.
187
188 Lemma node_next_hl_next_from hist fin i :
189 node_next_hl (next_from hist fin i) = loc_opt_hl (loc_at hist (S i)).
190 Proof.
191 unfold node_next_hl, next_from.
192 destruct fin, (decide (S i = length hist)) as [Hhist|Hhist]; simpl; try done.
193 - by rewrite bool_decide_true // /loc_at list_lookup_fmap lookup_ge_None_2; last lia.
194 - by rewrite bool_decide_false.
195 Qed.
196
197 Definition hist_repr (hist : list (loc * val)) (fin : bool) : iProp Σ :=
198 [∗ list] i ↦ '(ℓ, data) ∈ hist, node_repr ℓ data (next_from hist fin i).
199
200 Lemma hist_repr_peek_1 hist fin i ℓ data :
201 loc_at hist i = Some ℓ →
202 val_at hist i = Some data →
203 hist_repr hist fin -∗
204 node_repr ℓ data (next_from hist fin i) ∗
205 (node_repr ℓ data (next_from hist fin i) -∗ hist_repr hist fin).
206 Proof.
207 iIntros "%Hloc %Hval Hrepr".
208 pose proof (loc_at_val_at_combine Hloc Hval) as Hi.
209 iPoseProof (big_sepL_lookup_acc with "Hrepr") as "[Hnode Hclose]".
210 { apply Hi. }
211 iFrame.
212 Qed.
213
214 Lemma hist_repr_peek_2 hist fin i ℓ :
215 loc_at hist i = Some ℓ →
216 hist_repr hist fin -∗
217 ∃ data, node_repr ℓ data (next_from hist fin i) ∗
218 (node_repr ℓ data (next_from hist fin i) -∗ hist_repr hist fin).
219 Proof.
220 iIntros "%Hloc Hrepr".
221 assert (∃ v, val_at hist i = Some v) as [v Hval].
222 { by apply loc_at_val_at_Some in Hloc. }
223 iExists v. by iApply hist_repr_peek_1.
224 Qed.
225
226 Lemma hist_repr_peek_3 hist fin i ℓ :
227 loc_at hist i = Some ℓ →
228 hist_repr hist fin -∗
229 (ℓ +ₗ 1) ↦ node_next_hl (next_from hist fin i) ∗
230 ((ℓ +ₗ 1) ↦ node_next_hl (next_from hist fin i) -∗ hist_repr hist fin).
231 Proof.
232 iIntros "%Hloc Hrepr".
233 iDestruct (hist_repr_peek_2 with "[$]") as "(%v & @ & Hclose)"; first done.
234 iFrame. iIntros "Hnnext". iApply "Hclose". iFrame.
235 Qed.
236
237 Lemma loc_at_None hist pos :
238 loc_at hist pos = None → hist !! pos = None.
239 Proof.
240 rewrite /loc_at list_lookup_fmap.
241 by destruct (hist !! pos).
242 Qed.
243
244 Lemma loc_at_length hist pos :
245 loc_at hist pos = None → length hist ≤ pos.
246 Proof.
247 intros H%loc_at_None.
248 by apply lookup_ge_None.
249 Qed.
250
251 Lemma next_from_drop ℓvs fin n i :
252 next_from ℓvs fin (n + i) = next_from (drop n ℓvs) fin i.
253 Proof.
254 rewrite /next_from /loc_at list_lookup_fmap /= -list_lookup_fmap.
255 erewrite bool_decide_ext with (Q:=S i = length (drop n ℓvs)); last first.
256 { rewrite length_drop. lia. }
257 by rewrite fmap_drop list_lookup_fmap lookup_drop -list_lookup_fmap plus_n_Sm.
258 Qed.
259
260 Lemma hist_repr_proj hist i ℓ fin :
261 loc_at hist i = Some ℓ →
262 hist_repr hist fin -∗
263 (∃ v, (ℓ +ₗ 1) ↦ v) ∗ hist_repr (drop (S i) hist) fin.
264 Proof.
265 iIntros "%Hℓi Hrepr".
266 iDestruct (big_sepL_take_drop _ _ (S i) with "Hrepr") as "[Hrepr1 Hrepr2]".
267
268 rewrite /loc_at list_lookup_fmap in Hℓi.
269 destruct (hist !! i) as [[ℓ' v]|] eqn:Hi; last done.
270 simpl in *. injection Hℓi as ->.
271
272 iDestruct (big_sepL_lookup_acc with "Hrepr1") as "[Hrepr Hclose]".
273 { rewrite lookup_take_lt //. lia. }
274 iSimplifyEq. iDestruct "Hrepr" as "@". iFrame.
275 iClear "Hndata Hnfinal Hclose".
276
277 iAssert (hist_repr (drop (S i) hist) fin) with "[Hrepr2]" as "Hrepr2".
278 { unfold hist_repr. iApply (big_sepL_mono with "Hrepr2").
279 iIntros (k [ℓ' v'] Hk) "Hrepr".
280 rewrite -next_from_drop; first done. }
281 done.
282 Qed.
283
284 Lemma loc_at_inj_aux hist i j ℓ fin :
285 i < j →
286 loc_at hist i = Some ℓ →
287 loc_at hist j = Some ℓ →
288 hist_repr hist fin -∗
289 False.
290 Proof.
291 iIntros "%ij %Hloci %Hlocj Hrepr".
292 assert (i < length hist). { by eapply loc_at_Some_length. }
293 assert (j < length hist). { by eapply loc_at_Some_length. }
294 assert (∃ n, j = S i + n) as [n ->].
295 { exists (j - i - 1). lia. }
296 iPoseProof (hist_repr_proj hist i ℓ fin Hloci with "Hrepr") as "[[%ni Hℓi] Hrepr']".
297
298 assert (Hlocj' : loc_at (drop (S i) hist) n = Some ℓ).
299 { by apply loc_at_drop. }
300
301 iPoseProof (hist_repr_proj _ n ℓ fin Hlocj' with "Hrepr'") as "[[%nj Hℓj] _]".
302 by iCombine "Hℓi Hℓj" gives %[? _].
303 Qed.
304
305 Lemma loc_at_inj {hist i j ℓ fin} :
306 loc_at hist i = Some ℓ →
307 loc_at hist j = Some ℓ →
308 hist_repr hist fin -∗
309 ⌜i = j⌝.
310 Proof.
311 iIntros "%Hloci %Hlocj Hrepr".
312 destruct (loc_at_val_at_Some hist i ℓ Hloci) as [vi Hvali].
313 destruct (loc_at_val_at_Some hist j ℓ Hlocj) as [vj Hvalj].
314 destruct (decide (i < j)) as [Hij|Hij].
315 - (* i < j *)
316 by iPoseProof (loc_at_inj_aux with "Hrepr") as "H".
317 - (* i ≥ j *)
318 destruct (decide (j < i)) as [Hji|Hji].
319 + (* j < i *)
320 by iPoseProof (loc_at_inj_aux with "Hrepr") as "H".
321 + (* i = j *)
322 iPureIntro. lia.
323 Qed.
324
325 Definition queue_γs_dq (hist : list (loc * val)) (hpos : nat) (mfin : option val) : dfrac :=
326 match mfin with
327 | None => DfracOwn 1
328 | Some _ =>
329 if decide (S (S hpos) = length hist)
330 then DfracDiscarded
331 else DfracOwn 1
332 end.
333
334 Lemma queue_γs_dq_cases hist hpos mfin :
335 queue_γs_dq hist hpos mfin = DfracOwn 1 ∨
336 queue_γs_dq hist hpos mfin = DfracDiscarded.
337 Proof.
338 unfold queue_γs_dq.
339 destruct mfin, (decide (S (S hpos) = length hist));
340 (by left) || by right.
341 Qed.
342
343 Definition queue_repr_1 (γs : gstate) ℓ_q (vs : list val) (mfin : option val) : iProp Σ :=
344 ∃ (hist : list (loc * val)) (ℓ_head ℓ_tail : loc) (hpos tpos : nat),
345 ("Hhead" ∷ ℓ_q ↦ #ℓ_head) ∗
346 (* Not immediately clear whether this can be discarded when the queue is
347 finalized and otherwise emptied *)
348 ("Htail" ∷ (ℓ_q +ₗ 1) ↦ #ℓ_tail) ∗
349 ("Hrepr" ∷ hist_repr hist (bool_decide (is_Some mfin))) ∗
350 ("Hhist●" ∷ γs.(γ_hist) ↪●ML{queue_γs_dq hist hpos mfin} hist) ∗
351 ("Hhpos●" ∷ γs.(γ_hpos) ↪●MN{queue_γs_dq hist hpos mfin} hpos) ∗
352 ("%Hℓhpos" ∷ ⌜loc_at hist hpos = Some ℓ_head⌝) ∗
353 ("%Hℓtpos" ∷ ⌜loc_at hist tpos = Some ℓ_tail⌝) ∗
354 ("%Hvs" ∷ ⌜vs ++ option_list mfin = (drop (S hpos) hist).*2⌝).
355
356 Definition queue_fin_1 (γs : gstate) (fin : val) : iProp Σ :=
357 ∃ (hist : list (loc * val)) (hpos : nat),
358 ("Hhist" ∷ γs.(γ_hist) ↪●ML□ hist) ∗
359 ("Hhpos" ∷ γs.(γ_hpos) ↪●MN□ hpos) ∗
360 ("%Hfin" ∷ ⌜val_at hist (S hpos) = Some fin⌝).
361
362 Definition queue_repr ℓ_q (vs : list val) (mfin : option val) : iProp Σ :=
363 ∃ (γs : gstate), meta ℓ_q nroot γs ∗ queue_repr_1 γs ℓ_q vs mfin.
364
365 #[global] Instance queue_repr_timeless ℓ_q vs mfin : Timeless (queue_repr ℓ_q vs mfin) := _.
366
367 Definition queue_fin ℓ_q (fin : val) : iProp Σ :=
368 ∃ (γs : gstate), meta ℓ_q nroot γs ∗ queue_fin_1 γs fin.
369
370 #[global] Instance queue_fin_persistent ℓ_q fin : Persistent (queue_fin ℓ_q fin) := _.
371 #[global] Instance queue_fin_timeless ℓ_q fin : Timeless (queue_fin ℓ_q fin) := _.
372
373 Lemma queue_fin_obtain ℓ fin : queue_repr ℓ [] (Some fin) -∗ queue_fin ℓ fin.
374 Proof.
375 iIntros "(%γs & Hγs & @)". simplify_eq/=.
376 assert (Hlen : length (drop (S hpos) hist).*2 = 1) by rewrite -Hvs //.
377 rewrite fmap_drop length_drop length_fmap in Hlen.
378 case_decide; last lia. iFrame. iPureIntro.
379 by rewrite /val_at -[S hpos]Nat.add_0_r -lookup_drop -fmap_drop -Hvs.
380 Qed.
381
382 Lemma queue_fin_agree ℓ vs fin mfin :
383 queue_fin ℓ fin -∗
384 queue_repr ℓ vs mfin -∗
385 ⌜vs = []⌝ ∗ ⌜mfin = Some fin⌝.
386 Proof.
387 iIntros "(%γs & Hγs & @) (%γs' & Hγs' & @)".
388 iDestruct (meta_agree with "Hγs Hγs'") as "<- {Hγs'}".
389 iDestruct (mono_list_auth_own_agree with "Hhist Hhist●") as %[Hfracs <-].
390 iDestruct (mono_nat_auth_own_agree with "Hhpos Hhpos●") as %[_ <-].
391 iPureIntro.
392
393 unfold queue_γs_dq in Hfracs.
394 destruct mfin as [fin'|]; last done.
395 destruct (decide (S (S hpos) = length hist)); last done.
396
397 assert (Hlen : S (length vs) = 1).
398 { rewrite -Nat.add_1_r -(length_app _ [fin']) Hvs length_fmap length_drop -e. lia. }
399 destruct vs; last done. simplify_eq/=.
400
401 by rewrite -Hfin /val_at -[S hpos]Nat.add_0_r -lookup_drop -fmap_drop -Hvs.
402 Qed.
403
404 Lemma hist_weaken {γs} hist hpos mfin :
405 γs.(γ_hist) ↪●ML hist ==∗ γs.(γ_hist) ↪●ML{queue_γs_dq hist hpos mfin} hist.
406 Proof.
407 iIntros "Hhist".
408 destruct (queue_γs_dq_cases hist hpos mfin) as [-> | ->]; first done.
409 by iApply mono_list_auth_own_persist.
410 Qed.
411
412 Lemma hpos_weaken {γs hpos} hist mfin :
413 γs.(γ_hpos) ↪●MN hpos ==∗ γs.(γ_hpos) ↪●MN{queue_γs_dq hist hpos mfin} hpos.
414 Proof.
415 iIntros "Hhist".
416 destruct (queue_γs_dq_cases hist hpos mfin) as [-> | ->]; first done.
417 by iApply mono_nat_own_persist.
418 Qed.
419
420 Variant new_node_next := NonFinalType | FinalType.
421 Definition new_node_next_red (n : new_node_next) :=
422 match n with
423 | NonFinalType => Normal None
424 | FinalType => Final
425 end.
426 Instance new_node_next_eq_dec : EqDecision new_node_next.
427 Proof. solve_decision. Defined.
428
429 Lemma new_node_spec data (final : bool) :
430 {{{ True }}}
431 new_node data #final
432 {{{ (ℓ : loc), RET #ℓ; node_repr ℓ data (new_node_next_red (if final then FinalType else NonFinalType)) }}}.
433 Proof.
434 iIntros "%Φ _ HΦ". iUnfold new_node. wp_lam.
435 wp_alloc ℓ_node as "Hℓ_node"; first done.
436 iDestruct (array_cons with "Hℓ_node") as "[Hℓ_node0 Hℓ_node12]".
437 iDestruct (array_cons with "Hℓ_node12") as "[Hℓ_node1 Hℓ_node2]".
438 iDestruct (array_cons with "Hℓ_node2") as "[Hℓ_node2 _]".
439 rewrite Loc.add_assoc.
440 wp_let. do 3 wp_store.
441 iMod (pointsto_persist with "Hℓ_node0") as "Hℓ_node0".
442 iMod (pointsto_persist with "Hℓ_node2") as "Hℓ_node2".
443 iModIntro. iApply "HΦ". destruct final; by iFrame.
444 Qed.
445
446 Lemma new_spec :
447 {{{ True }}}
448 new #()
449 {{{ (ℓ : loc), RET #ℓ; queue_repr ℓ [] None }}}.
450 Proof.
451 iIntros "%Φ _ HΦ". iUnfold new.
452 wp_lam. wp_apply (new_node_spec with "[//]") as (ℓ_node) "Hnode". wp_let.
453
454 set ℓ_head := ℓ_node. set ℓ_tail := ℓ_node.
455 set hpos := 0. set tpos := 0.
456 set hist := [(ℓ_node, #())] : list (loc * val).
457 iAssert (hist_repr hist false) with "[$Hnode //]" as "Hrepr".
458
459 iMod (mono_list_own_alloc hist) as "[%γ_hist [Hhist● _]]".
460 iMod (mono_nat_own_alloc hpos) as "[%γ_hpos [Hhpos● _]]".
461 set γs := {| γ_hist := γ_hist; γ_hpos := γ_hpos |}.
462
463 iApply wp_fupd. iApply wp_allocN; [lia|done|].
464 iIntros "!> %ℓ [Hℓ [Htok _]]".
465 iDestruct (array_cons with "Hℓ") as "[Hℓ0 Hℓ1]".
466 iDestruct (array_cons with "Hℓ1") as "[Hℓ1 _]".
467 rewrite Loc.add_0.
468
469 iMod (meta_set ⊤ ℓ γs nroot with "Htok") as "Hmeta"; first done.
470
471 iApply "HΦ". iModIntro. iFrame. by iExists tpos.
472 Qed.
473
474 Lemma try_bump_tail_spec hist0 tpos ℓ_old ℓ_new ℓ_q γs :
475 loc_at hist0 tpos = Some ℓ_old →
476 loc_at hist0 (S tpos) = Some ℓ_new →
477 γs.(γ_hist) ↪◯ML hist0 -∗
478 <<{ ∀∀ vs mfin, queue_repr_1 γs ℓ_q vs mfin }>>
479 CAS #(ℓ_q +ₗ 1) #ℓ_old #ℓ_new @ ∅
480 <<{ ∃∃ (b : bool), queue_repr_1 γs ℓ_q vs mfin | RET #b }>>.
481 Proof.
482 iIntros "%Hold %Hnew #Hhist◯ %Φ AU".
483 wp_bind (CmpXchg _ _ _)%E.
484 iMod "AU" as "(%vs & %fin & (%hist1 & %ℓ_head & %ℓ_tail & %hpos & %tpos' & @) & [_ Hclose])".
485 iAssert ⌜hist0 `prefix_of` hist1⌝%I as %Hhist01.
486 { by iDestruct (mono_list_auth_lb_own_valid with "Hhist● Hhist◯") as "[_ ?]". }
487
488 destruct (decide (ℓ_tail = ℓ_old)) as [->|].
489 - (* The tail has not been updated yet *)
490 wp_cmpxchg_suc.
491
492 iAssert (queue_repr_1 γs ℓ_q vs fin) with "[$Hhead $Htail $Hhist● $Hhpos● $Hrepr]" as "Hq".
493 { iPureIntro.
494 repeat split; try done || lia.
495 exists (S tpos). repeat split; try done.
496 by eapply loc_at_prefix. }
497 iMod ("Hclose" with "[$Hq]") as "HΦ".
498 iModIntro. wp_pures. iApply "HΦ".
499 - (* The tail has been updated in the meantime *)
500 wp_cmpxchg_fail.
501 iAssert (queue_repr_1 γs ℓ_q vs fin) with "[$Hhead $Htail $Hhist● $Hhpos● $Hrepr]" as "Hq".
502 { iExists tpos'. by iFrameNamed. }
503 iMod ("Hclose" with "[$Hq]") as "HΦ".
504 iModIntro. wp_pures. iApply "HΦ".
505 Qed.
506
507 (* Given a history that is represented, after updating the [next]
508 pointer of the current tail node to a new tail node, we obtain a
509 new (extended) history (with the new tail node appended). *)
510 Lemma hist_repr_snoc hist tpos (ℓ_tail ℓ_new : loc) data next :
511 length hist = S tpos →
512 loc_at hist tpos = Some ℓ_tail →
513 node_repr ℓ_new data (new_node_next_red next) -∗
514 hist_repr hist false -∗
515 (ℓ_tail +ₗ 1) ↦ node_next_hl (Normal None) ∗
516 ((ℓ_tail +ₗ 1) ↦ node_next_hl (Normal (Some ℓ_new)) -∗ hist_repr (hist ++ [(ℓ_new, data)]) (bool_decide (next = FinalType))).
517 Proof.
518 unfold loc_at.
519 iIntros "%Hhistlen %Hloc @ Hhist".
520 rewrite list_lookup_fmap in Hloc.
521 destruct (hist !! tpos) as [[ℓ_tail' v_tail]|] eqn:Htpos; last done.
522 injection Hloc as ->.
523 apply list_elem_of_split_length in Htpos as (hist' & empty & -> & Htpos).
524 rewrite length_app length_cons -Htpos in Hhistlen.
525 assert (empty = []) as ->. { apply nil_length_inv. lia. }
526 clear Hhistlen Htpos.
527
528 iPoseProof (big_sepL_snoc with "Hhist") as "[Hinit Htail]".
529 iNamedSuffix "Htail" "_tail".
530
531 iSimplifyEq.
532 assert (loc_at (hist' ++ [(ℓ_tail, v_tail)]) (S (length hist')) = None) as ->.
533 { apply lookup_ge_None_2. rewrite length_fmap length_app length_cons /=. lia. }
534 iFrame "Hnnext_tail". iIntros "Hnnext_tail".
535 iSimplifyEq. rewrite /hist_repr.
536 iApply big_sepL_snoc.
537 iSplitR "Hndata Hnfinal Hnnext".
538 - iApply big_sepL_snoc. iSplitL "Hinit".
539 + iApply (big_sepL_mono with "Hinit").
540 iIntros (k [ℓ v] Hk) "Hrepr".
541 unfold next_from. simpl. rewrite [bool_decide (S k = _)]bool_decide_false; last first.
542 { apply lookup_lt_Some in Hk. rewrite !length_app /=. lia. }
543 rewrite andb_false_r /=.
544 assert (loc_at ((hist' ++ [(ℓ_tail, v_tail)]) ++ [(ℓ_new, data)]) (S k) = loc_at (hist' ++ [(ℓ_tail, v_tail)]) (S k)) as ->.
545 { rewrite /loc_at !list_lookup_fmap lookup_app_l // length_app /=.
546 apply lookup_lt_Some in Hk. lia. }
547 done.
548 + iFrame.
549 rewrite /next_from /= [bool_decide (S (length hist') = _)]bool_decide_false; last first.
550 { rewrite !length_app /=. lia. }
551 rewrite andb_false_r /= /loc_at list_lookup_fmap lookup_app_r; last first.
552 { rewrite length_app /=. lia. }
553 rewrite length_app /= Nat.add_1_r Nat.sub_diag /=.
554 by iFrame.
555 - iFrame.
556 rewrite /next_from /= /loc_at length_app /= Nat.add_1_r list_lookup_fmap lookup_app_r.
557 * rewrite !length_app /= !Nat.add_1_r [bool_decide (S _ = S _)]bool_decide_true //
558 andb_true_r Nat.sub_succ -Arith_base.minus_Sn_m_stt // Nat.sub_diag /=.
559 destruct next; simpl; iFrame.
560 * rewrite length_app /= Nat.add_1_r. lia.
561 Qed.
562
563 Definition iffinal {A} (n : new_node_next) (a b : A) :=
564 match n with
565 | FinalType => a
566 | NonFinalType => b
567 end.
568
569 Lemma set_tail_spec (ℓ_q ℓ_node : loc) data next :
570 node_repr ℓ_node data (new_node_next_red next) -∗
571 <<{ ∀∀ vs, queue_repr ℓ_q vs None }>>
572 set_tail #ℓ_q #ℓ_node @ ∅
573 <<{ queue_repr ℓ_q (vs ++ iffinal next [] [data]) (iffinal next (Some data) None) | RET #() }>>.
574 Proof.
575 iIntros "@ %Φ AU". iLöb as "IH". wp_rec.
576
577 wp_pures. wp_bind (! _)%E.
578 iMod "AU" as "(%vs & (%γs & #Hγs & %hist0 & %ℓ_head & %ℓ_tail & %hpos & %tpos & @) & [Hclose _])".
579 iDestruct (mono_list_lb_own_get with "Hhist●") as "#Hhist0◯".
580 wp_load. iSimpl in "Hrepr".
581 rename Hℓtpos into Hℓtpos0.
582 iAssert (queue_repr_1 γs ℓ_q vs None) with "[$Hhead $Htail $Hhist● $Hhpos● $Hrepr]" as "Hq".
583 { iExists tpos. by iFrameNamed. }
584 iMod ("Hclose" with "[$]") as "AU". clear Hvs Hℓhpos hpos vs ℓ_head.
585 iModIntro. wp_let. wp_pure.
586
587 wp_bind (! _)%E.
588 iMod "AU" as "(%vs & (%γs' & Hγs' & %hist2 & %ℓ_head & %ℓ_tail'' & %hpos & %tpos'' & @) & [Hclose _])".
589 iDestruct (meta_agree with "Hγs Hγs'") as "<- {Hγs'}".
590 iDestruct (mono_list_auth_lb_own_valid with "Hhist● Hhist0◯") as %Hhist02.
591 iDestruct (mono_list_lb_own_get with "Hhist●") as "#Hhist2◯".
592 destruct Hhist02 as [_ Hhist02]. rename Hℓtpos into Hℓtpos2.
593 assert (Hℓtpos0'' : loc_at hist2 tpos = Some ℓ_tail).
594 { by eapply loc_at_prefix. } clear Hℓtpos0.
595 wp_pures.
596 iDestruct (hist_repr_peek_2 with "[$Hrepr]") as "(%w & Hnrepr & Hrepr)"; first done.
597 iNamedSuffix "Hnrepr" "_tail".
598 wp_load.
599 iDestruct "Hnfinal_tail" as "#Hnfinal_tail2".
600 iPoseProof ("Hrepr" with "[$]") as "Hrepr".
601 iAssert (queue_repr_1 γs ℓ_q vs None) with "[$Hhead $Htail $Hhist● $Hhpos● $Hrepr]" as "Hq".
602 { iExists tpos''. by iFrameNamed. }
603 iMod ("Hclose" with "[$]") as "AU". clear Hvs Hℓhpos hpos vs ℓ_head.
604 iModIntro.
605
606 destruct (next_from hist2 false tpos) as [[ℓ_next|]|] eqn:Htpos2; last done.
607 + (* it is not the last node *)
608 simpl. apply next_from_normal in Htpos2 as [Hnext HStpos2]. rewrite HStpos2 /=.
609
610 wp_pures. wp_bind (Snd (CmpXchg _ _ _))%E.
611 awp_apply (try_bump_tail_spec with "[//]").
612 { apply Hℓtpos0''. }
613 { done. }
614 rewrite /atomic_acc /=.
615 iMod "AU" as "(%vs & (%γs' & Hγs' & Hrepr) & [Hclose _])".
616 iDestruct (meta_agree with "Hγs Hγs'") as "<- {Hγs'}".
617 iModIntro. iExists vs. iFrame "Hrepr". iSplit.
618 * iFrame. iIntros "Hrepr". by iApply ("Hclose" with "[$Hrepr]").
619 * iIntros "%b Hrepr".
620 iMod ("Hclose" with "[$Hrepr //]") as "AU".
621 iModIntro. wp_pures.
622 by iApply ("IH" with "[$] [$] [$]").
623 + (* it is the last (non-final) node *)
624 simpl. apply next_from_normal in Htpos2 as [Hnext HStpos2]. rewrite HStpos2 /=.
625 wp_pures. wp_bind (CmpXchg _ _ _)%E.
626
627 iMod "AU" as "(%vs & (%γs' & Hγs' & %hist3 & %ℓ_head & %ℓ_tail''' & %hpos & %tpos''' & @) & Hclose)".
628 iDestruct (meta_agree with "Hγs Hγs'") as "<- {Hγs'}".
629 iDestruct (mono_list_auth_lb_own_valid with "Hhist● Hhist2◯") as %Hhist23.
630 destruct Hhist23 as [_ Hhist23]. rename Hℓtpos into Hℓtpos3.
631
632 destruct (loc_at hist3 (S tpos)) as [ℓ_tail''''|] eqn:Hrace.
633 * (* Another item has been enqueued in the meantime, so the CAS is poised to fail. *)
634 iDestruct "Hclose" as "[Hclose _]".
635
636 iDestruct (hist_repr_peek_3 with "[$Hrepr]") as "[Hℓ_tail1 Hrepr]".
637 { eapply prefix_lookup_Some; first apply Hℓtpos0''. by apply prefix_of_fmap. }
638 rewrite /next_from [bool_decide (S _ = _)]bool_decide_false; last first.
639 { apply lookup_lt_Some in Hrace. rewrite length_fmap in Hrace. lia. }
640 rewrite andb_false_r Hrace /=.
641 wp_cmpxchg_fail.
642 iSpecialize ("Hrepr" with "Hℓ_tail1").
643 iAssert (queue_repr_1 γs ℓ_q vs None) with "[$Hhead $Htail $Hhist● $Hhpos● $Hrepr]" as "Hq".
644 { iExists tpos'''. by iFrameNamed. }
645 iMod ("Hclose" with "[$]") as "AU". iModIntro.
646 wp_pures. iApply ("IH" with "Hndata Hnnext Hnfinal AU").
647 * (* This node is still the tail, so the CAS will succeed. *)
648 iDestruct "Hclose" as "[_ Hclose]".
649
650 iAssert ⌜length hist3 = S tpos⌝%I as %Hhist3.
651 { apply loc_at_length in Hrace as Hhist3.
652 iPureIntro. apply loc_at_prefix with (xs':=hist3) in Hℓtpos0''; last done.
653 apply lookup_lt_Some in Hℓtpos0''. rewrite length_fmap in Hℓtpos0''. lia. }
654
655 iDestruct (hist_repr_peek_2 with "[$Hrepr]") as "(%w' & Hℓ_tail3 & Hrepr)".
656 { eapply prefix_lookup_Some; first apply Hℓtpos0''. by apply prefix_of_fmap. }
657 rewrite /next_from [bool_decide (S _ = _)]bool_decide_true // andb_true_r Hrace /=.
658 iNamedSuffix "Hℓ_tail3" "_tail3".
659 iPoseProof ("Hrepr" with "[$]") as "Hrepr". clear w.
660
661 iPoseProof (hist_repr_snoc with "[$Hndata $Hnfinal $Hnnext] [$Hrepr]") as "[Htnode Henq]".
662 { apply Hhist3. }
663 { eapply prefix_lookup_Some. apply Hℓtpos0''. by apply prefix_of_fmap. }
664 wp_cmpxchg_suc. iSpecialize ("Henq" with "Htnode").
665
666 pose mfin := iffinal next (Some data) None.
667
668 iMod (mono_list_auth_own_update_app [(ℓ_node, data)] with "Hhist●") as "[Hhist● _]".
669 iMod (hpos_weaken (hist3 ++ [(ℓ_node, data)]) mfin with "Hhpos●") as "Hhpos●".
670 iMod (hist_weaken (hist3 ++ [(ℓ_node, data)]) hpos mfin with "Hhist●") as "Hhist●".
671 replace (bool_decide (next = FinalType)) with (bool_decide (is_Some mfin)); last first.
672 { apply bool_decide_ext. destruct next; by cbn. }
673
674 iAssert (queue_repr_1 γs ℓ_q (vs ++ iffinal next [] [data]) mfin) with "[$Hhead $Htail $Hhist● $Hhpos● $Henq]" as "Hq".
675 { iExists tpos'''. iPureIntro.
676 repeat split; try done.
677 - eapply loc_at_prefix; first done.
678 by apply prefix_app_r.
679 - eapply loc_at_prefix; first done.
680 by apply prefix_app_r.
681 - rewrite drop_app fmap_app -Hvs. rewrite /= app_nil_r -app_assoc.
682 f_equal.
683 assert (Hhpos : hpos < length hist3).
684 { apply lookup_lt_Some in Hℓhpos.
685 by rewrite length_fmap in Hℓhpos. }
686 assert (S hpos - length hist3 = 0) as -> by lia.
687 simpl. by destruct next. }
688 iMod ("Hclose" with "[$]") as "HΦ".
689 iModIntro. wp_pures. done.
690 Qed.
691
692 Lemma enqueue_spec (ℓ_q : loc) (data : val) :
693 ⊢ <<{ ∀∀ vs, queue_repr ℓ_q vs None }>>
694 enqueue #ℓ_q data @ ∅
695 <<{ queue_repr ℓ_q (vs ++ [data]) None | RET #() }>>.
696 Proof.
697 iIntros "%Φ AU". wp_lam. wp_pures.
698 wp_apply (new_node_spec with "[//]") as "%ℓ_node Hnode".
699 awp_apply (set_tail_spec with "[$Hnode]").
700 rewrite /atomic_acc /=. iMod "AU" as "(%vs & Hrepr & Hclose)".
701 iModIntro. iFrame.
702 Qed.
703
704 Lemma finalize_spec (ℓ_q : loc) (data : val) :
705 ⊢ <<{ ∀∀ vs, queue_repr ℓ_q vs None }>>
706 finalize #ℓ_q data @ ∅
707 <<{ queue_repr ℓ_q vs (Some data) | RET #() }>>.
708 Proof.
709 iIntros "%Φ AU". wp_lam. wp_pures.
710 wp_apply (new_node_spec with "[//]") as "%ℓ_node Hnode".
711 awp_apply (set_tail_spec with "[$Hnode]").
712 rewrite /atomic_acc /=. iMod "AU" as "(%vs & Hrepr & Hclose)".
713 iModIntro. iFrame. by rewrite app_nil_r.
714 Qed.
715
716 Lemma try_dequeue_spec (ℓ_q : loc) :
717 ⊢ <<{ ∀∀ vs mfin, queue_repr ℓ_q vs mfin }>>
718 try_dequeue #ℓ_q @ ∅
719 <<{ queue_repr ℓ_q (tail vs) mfin
720 | RET (if head vs is Some v then InjLV v else InjRV (val_opt_hl mfin)) }>>.
721 Proof.
722 iIntros "%Φ AU". iLöb as "IH". wp_rec.
723
724 wp_bind (! _)%E.
725 iMod "AU" as "(%vs0 & %fin0 & (%γs & #Hγs & %hist0 & %ℓ_head0 & %ℓ_tail0 & %hpos0 & %tpos0 & @) & [Hclose _])".
726 iDestruct (mono_list_lb_own_get with "Hhist●") as "#Hhist0◯".
727 iDestruct (mono_nat_lb_own_get with "Hhpos●") as "#Hhpos0◯".
728 rename Hℓhpos into Hℓhpos0.
729 wp_load.
730 iMod ("Hclose" with "[$Hhead $Htail $Hhist● $Hhpos● $Hrepr $Hγs]") as "AU".
731 { iExists tpos0. by iFrameNamed. }
732 iModIntro. clear fin0 vs0 Hvs tpos0 Hℓtpos ℓ_tail0.
733
734 wp_pures. wp_bind (! _)%E.
735 iMod "AU" as "(%vs1 & %fin1 & (%γs' & Hγs' & %hist1 & %ℓ_head1 & %ℓ_tail1 & %hpos1 & %tpos1 & @) & Hclose)".
736 iDestruct (meta_agree with "Hγs Hγs'") as "<- {Hγs'}".
737 iDestruct (mono_list_lb_own_get with "Hhist●") as "#Hhist1◯".
738 iDestruct (mono_nat_auth_lb_own_valid with "Hhpos● Hhpos0◯") as %Hhpos01.
739 iDestruct (mono_list_auth_lb_own_valid with "Hhist● Hhist0◯") as %Hhist01.
740 destruct Hhpos01 as [_ Hhpos01]. destruct Hhist01 as [_ Hhist01].
741 assert (Hℓhpos0' : loc_at hist1 hpos0 = Some ℓ_head0).
742 { by eapply loc_at_prefix. } clear Hℓhpos0.
743 iDestruct (hist_repr_peek_2 with "[$Hrepr]") as "(%u & @ & Hrepr)"; first done.
744 wp_load.
745 iSpecialize ("Hrepr" with "[$]").
746
747 rewrite node_next_hl_next_from.
748 destruct (loc_at hist1 (S hpos0)) as [ℓ_headS0|] eqn:Hℓ_headS0.
749 - simpl. iDestruct "Hclose" as "[Hclose _]".
750 iMod ("Hclose" with "[$Hhead $Htail $Hhist● $Hhpos● $Hrepr $Hγs]") as "AU".
751 { iExists tpos1. by iFrameNamed. }
752 iModIntro. clear u fin1 vs1 Hvs tpos1 Hℓtpos ℓ_tail1.
753
754 wp_pures. wp_bind (! _)%E.
755 iMod "AU" as "(%vs2 & %fin2 & (%γs' & Hγs' & %hist2 & %ℓ_head2 & %ℓ_tail2 & %hpos2 & %tpos2 & @) & Hclose)".
756 iDestruct (meta_agree with "Hγs Hγs'") as "<- {Hγs'}".
757 iDestruct (mono_list_lb_own_get with "Hhist●") as "#Hhist2◯".
758 iDestruct (mono_nat_auth_lb_own_valid with "Hhpos● Hhpos0◯") as %Hhpos02.
759 iDestruct (mono_list_auth_lb_own_valid with "Hhist● Hhist1◯") as %Hhist12.
760 destruct Hhpos02 as [_ Hhpos02]. destruct Hhist12 as [_ Hhist12].
761 assert (Hℓ_headS0' : loc_at hist2 (S hpos0) = Some ℓ_headS0).
762 { by eapply loc_at_prefix. } clear Hℓ_headS0.
763 apply loc_at_val_at_Some in Hℓ_headS0' as Hval_headS0'.
764 destruct Hval_headS0' as [w Hval_headS0'].
765 iDestruct (hist_repr_peek_1 with "[$Hrepr]") as "(@ & Hrepr)"; try done.
766 iDestruct "Hndata" as "#Hndata_head".
767 wp_load.
768
769 destruct (next_from hist2 (bool_decide (is_Some fin2)) (S hpos0)) as [mℓ_next|] eqn:Hnext2.
770 + iDestruct "Hclose" as "[Hclose _]".
771 iEval (rewrite bool_decide_false //).
772
773 iDestruct "Hnfinal" as "#Hnfinal_head".
774 iEval (rewrite bool_decide_false //) in "Hnfinal_head".
775
776 iSpecialize ("Hrepr" with "[$]").
777 iMod ("Hclose" with "[$Hhead $Htail $Hhist● $Hhpos● $Hrepr $Hγs]") as "AU".
778 { iExists tpos2. by iFrameNamed. }
779 iModIntro.
780 clear fin2 vs2 Hvs tpos2 Hℓtpos ℓ_tail2 Hnext2.
781
782 wp_pures. wp_load. wp_pures.
783
784 wp_bind (CmpXchg _ _ _)%E.
785 iMod "AU" as "(%vs3 & %fin3 & (%γs' & Hγs' & %hist3 & %ℓ_head3 & %ℓ_tail3 & %hpos3 & %tpos3 & @) & Hclose)".
786 iDestruct (meta_agree with "Hγs Hγs'") as "<- {Hγs'}".
787 iDestruct (mono_list_auth_lb_own_valid with "Hhist● Hhist2◯") as %Hhist23.
788 destruct Hhist23 as [_ Hhist23].
789 assert (Hhist13 : hist1 `prefix_of` hist3).
790 { by trans hist2. }
791
792 destruct (decide (ℓ_head0 = ℓ_head3)) as [->|Hhead03].
793 * iDestruct "Hclose" as "[_ Hclose]".
794
795 wp_cmpxchg_suc.
796
797 assert (Hℓhpos0'' : loc_at hist3 hpos0 = Some ℓ_head3).
798 { by eapply loc_at_prefix. } clear Hℓhpos0'.
799 iAssert ⌜hpos0 = hpos3⌝%I as %->.
800 { by iApply (loc_at_inj with "Hrepr"). }
801
802 destruct (decide (length (vs3 ++ option_list fin3) = 1)) as [Hvs3|Hvs3].
803 -- destruct fin3 eqn:Hfin3.
804 ++ assert (Hℓ_headS0'' : loc_at hist3 (S hpos3) = Some ℓ_headS0).
805 { by eapply loc_at_prefix. } clear Hℓ_headS0'.
806 assert (Hval_headS0'' : val_at hist3 (S hpos3) = Some w).
807 { by eapply val_at_prefix. } clear Hval_headS0'.
808
809 simplify_eq/=.
810 destruct vs3; last first.
811 { rewrite length_app /= Nat.add_1_r in Hvs3. lia. }
812
813 assert (length hist3 = S (S hpos3)).
814 { apply (f_equal length), symmetry in Hvs.
815 rewrite /= length_fmap length_drop in Hvs. lia. }
816
817 iDestruct (hist_repr_peek_1 with "[$Hrepr]") as "(@ & Hrepr)"; try done.
818 iClear "Hnnext".
819 rewrite /next_from !andb_true_l [bool_decide (S _ = _)]bool_decide_true //=.
820 by iCombine "Hnfinal_head Hnfinal" gives "[_ %contra]".
821 ++ simplify_eq/=. rewrite app_nil_r in Hvs Hvs3.
822
823 iMod (mono_nat_own_update (S hpos3) with "Hhpos●") as "[Hhpos● _]". { lia. }
824 iMod ("Hclose" with "[$Hhead $Htail $Hhist● $Hhpos● $Hrepr $Hγs]") as "HΦ".
825 { iExists tpos3. iFrameNamed.
826 iPureIntro. repeat split; try done.
827 - by eapply loc_at_prefix.
828 - by rewrite /= fmap_drop /= -Nat.add_1_r -drop_drop -fmap_drop -Hvs app_nil_r. }
829
830 iModIntro. wp_pures.
831
832 assert (Hval_headS0'' : val_at hist3 (S hpos3) = Some w).
833 { by eapply val_at_prefix. } clear Hval_headS0'.
834 unfold val_at in Hval_headS0''.
835 destruct vs3; try done.
836 rewrite -[S hpos3]Nat.add_0_r -lookup_drop -fmap_drop -Hvs /= in Hval_headS0''.
837 by simplify_eq/=.
838 -- assert (S (S hpos3) ≠ length hist3).
839 { rewrite Hvs length_fmap length_drop in Hvs3. lia. }
840
841 assert (queue_γs_dq hist3 hpos3 fin3 = DfracOwn 1) as ->.
842 { unfold queue_γs_dq. by repeat case_match. }
843 iMod (mono_nat_own_update (S hpos3) with "Hhpos●") as "[Hhpos● _]". { lia. }
844 iMod (hpos_weaken hist3 fin3 with "Hhpos●") as "Hhpos●".
845 iMod (hist_weaken hist3 (S hpos3) fin3 with "Hhist●") as "Hhist●".
846
847 iMod ("Hclose" with "[$Hhead $Htail $Hhist● $Hhpos● $Hrepr $Hγs]") as "HΦ".
848 { iExists tpos3. iFrameNamed.
849 iPureIntro. repeat split; try done.
850 - by eapply loc_at_prefix.
851 - rewrite -Nat.add_1_r -drop_drop fmap_drop -Hvs.
852 destruct fin3; last by rewrite /= !app_nil_r.
853 by destruct vs3. }
854
855 iModIntro. wp_pures.
856
857 assert (Hval_headS0'' : val_at hist3 (S hpos3) = Some w).
858 { by eapply val_at_prefix. } clear Hval_headS0'.
859 unfold val_at in Hval_headS0''.
860 rewrite -[S hpos3]Nat.add_0_r -lookup_drop -fmap_drop -Hvs in Hval_headS0''.
861
862 destruct vs3; simplify_eq/=; last done.
863 by destruct fin3.
864
865 * iDestruct "Hclose" as "[Hclose _]".
866
867 wp_cmpxchg_fail.
868
869 iMod ("Hclose" with "[$Hhead $Htail $Hhist● $Hhpos● $Hrepr $Hγs]") as "AU".
870 { iExists tpos3. by iFrameNamed. }
871
872 iModIntro. wp_pures. iApply ("IH" with "AU").
873
874 + iDestruct "Hclose" as "[_ Hclose]".
875
876 destruct fin2 as [fin2|]; last done. simplify_eq/=.
877 assert (Hhist2 : length hist2 = S (S hpos0)).
878 { destruct (decide (length hist2 = S (S hpos0))); first done.
879 by rewrite /next_from bool_decide_false in Hnext2. }
880 assert (S hpos2 < length hist2).
881 { rewrite -(length_fmap snd).
882 apply lookup_lt_is_Some_1.
883 rewrite -[S hpos2]Nat.add_0_r -lookup_drop -fmap_drop -Hvs.
884 by destruct vs2, fin2. }
885 assert (hpos0 = hpos2) as -> by lia.
886 assert (Hvs2 : length vs2 = 0).
887 { apply eq_add_S. rewrite -Nat.add_1_r -(length_app _ [fin2]) Hvs length_fmap length_drop Hhist2. lia. }
888 destruct vs2; last done. clear Hvs2.
889
890 iSpecialize ("Hrepr" with "[$]").
891 iMod ("Hclose" with "[$Hhead $Htail $Hhist● $Hhpos● $Hrepr $Hγs]") as "HΦ".
892 { iExists tpos2. by iFrameNamed. }
893
894 iModIntro. clear tpos2 Hℓhpos Hℓtpos ℓ_tail2.
895
896 wp_pures. wp_load.
897 rewrite /val_at in Hval_headS0'.
898 rewrite -[S hpos2]Nat.add_0_r -lookup_drop -fmap_drop -Hvs in Hval_headS0'.
899 simplify_eq/=. wp_pures. iApply "HΦ".
900 - apply loc_at_length in Hℓ_headS0 as Hhistlen.
901 rewrite drop_ge /= in Hvs; last lia. destruct vs1, fin1; try done.
902 simplify_eq/=.
903
904 iDestruct "Hclose" as "[_ Hclose]".
905 iMod ("Hclose" with "[$Hhead $Htail $Hhist● $Hhpos● $Hrepr $Hγs]") as "HΦ".
906 { iExists tpos1. iFrameNamed. iPureIntro.
907 rewrite drop_ge //=. lia. }
908
909 iModIntro. wp_pures. iApply "HΦ".
910 Qed.
911
912End fin_queue.
913
914Definition fin_queue_hl :=
915 {| fin_queue_spec.new := new;
916 fin_queue_spec.enqueue := enqueue;
917 fin_queue_spec.finalize := finalize;
918 fin_queue_spec.try_dequeue := try_dequeue; |}.
919
920Definition fin_queue_iris `{!heapGS Σ, !fin_queueG Σ} : fin_queue_spec.fin_queue_iris Σ fin_queue_hl.
921Proof.
922 refine (FinQueueIris _ _
923 fin_queue_hl _ _ _ _ _
924 queue_fin_obtain
925 queue_fin_agree
926 new_spec
927 enqueue_spec
928 finalize_spec
929 try_dequeue_spec).
930Defined.
931
932#[global] Typeclasses Opaque queue_repr queue_fin.