diff --git a/rocq-brick-libstdcpp/test/dune.inc b/rocq-brick-libstdcpp/test/dune.inc index a5b255d..b4ecf39 100644 --- a/rocq-brick-libstdcpp/test/dune.inc +++ b/rocq-brick-libstdcpp/test/dune.inc @@ -19,21 +19,84 @@ ) (subdir geeks_for_geeks_examples (rule - (targets N0_hello_world_cpp.v) + (targets N12_area_cpp.v) (alias test_ast) - (deps (:input N0_hello_world.cpp) (glob_files_rec ../*.hpp) (universe)) + (deps (:input N12_area.cpp) (glob_files_rec ../*.hpp) (universe)) (action - (run cpp2v -v %{input} -o N0_hello_world_cpp.v --no-elaborate -- -std=c++20 -stdlib=libstdc++ ))) - (alias (name srcs) (deps N0_hello_world.cpp)) + (run cpp2v -v %{input} -o N12_area_cpp.v --no-elaborate -- -std=c++20 -stdlib=libstdc++ ))) + (alias (name srcs) (deps N12_area.cpp)) ) (subdir geeks_for_geeks_examples (rule - (targets N2_input_cpp.v) + (targets N1_hello_world_cpp.v) (alias test_ast) - (deps (:input N2_input.cpp) (glob_files_rec ../*.hpp) (universe)) + (deps (:input N1_hello_world.cpp) (glob_files_rec ../*.hpp) (universe)) (action - (run cpp2v -v %{input} -o N2_input_cpp.v --no-elaborate -- -std=c++20 -stdlib=libstdc++ ))) - (alias (name srcs) (deps N2_input.cpp)) + (run cpp2v -v %{input} -o N1_hello_world_cpp.v --no-elaborate -- -std=c++20 -stdlib=libstdc++ ))) + (alias (name srcs) (deps N1_hello_world.cpp)) +) +(subdir geeks_for_geeks_examples + (rule + (targets N3_input_cpp.v) + (alias test_ast) + (deps (:input N3_input.cpp) (glob_files_rec ../*.hpp) (universe)) + (action + (run cpp2v -v %{input} -o N3_input_cpp.v --no-elaborate -- -std=c++20 -stdlib=libstdc++ ))) + (alias (name srcs) (deps N3_input.cpp)) +) +(subdir geeks_for_geeks_examples + (rule + (targets N4_sum_cpp.v) + (alias test_ast) + (deps (:input N4_sum.cpp) (glob_files_rec ../*.hpp) (universe)) + (action + (run cpp2v -v %{input} -o N4_sum_cpp.v --no-elaborate -- -std=c++20 -stdlib=libstdc++ ))) + (alias (name srcs) (deps N4_sum.cpp)) +) +(subdir geeks_for_geeks_examples + (rule + (targets N4_sum_a_cpp.v) + (alias test_ast) + (deps (:input N4_sum_a.cpp) (glob_files_rec ../*.hpp) (universe)) + (action + (run cpp2v -v %{input} -o N4_sum_a_cpp.v --no-elaborate -- -std=c++20 -stdlib=libstdc++ ))) + (alias (name srcs) (deps N4_sum_a.cpp)) +) +(subdir geeks_for_geeks_examples + (rule + (targets N5_swap_cpp.v) + (alias test_ast) + (deps (:input N5_swap.cpp) (glob_files_rec ../*.hpp) (universe)) + (action + (run cpp2v -v %{input} -o N5_swap_cpp.v --no-elaborate -- -std=c++20 -stdlib=libstdc++ ))) + (alias (name srcs) (deps N5_swap.cpp)) +) +(subdir geeks_for_geeks_examples + (rule + (targets N6_print_sizeof_cpp.v) + (alias test_ast) + (deps (:input N6_print_sizeof.cpp) (glob_files_rec ../*.hpp) (universe)) + (action + (run cpp2v -v %{input} -o N6_print_sizeof_cpp.v --no-elaborate -- -std=c++20 -stdlib=libstdc++ ))) + (alias (name srcs) (deps N6_print_sizeof.cpp)) +) +(subdir geeks_for_geeks_examples + (rule + (targets N8_ascii_value_cast_cpp.v) + (alias test_ast) + (deps (:input N8_ascii_value_cast.cpp) (glob_files_rec ../*.hpp) (universe)) + (action + (run cpp2v -v %{input} -o N8_ascii_value_cast_cpp.v --no-elaborate -- -std=c++20 -stdlib=libstdc++ ))) + (alias (name srcs) (deps N8_ascii_value_cast.cpp)) +) +(subdir geeks_for_geeks_examples + (rule + (targets N8_ascii_value_printf_cpp.v) + (alias test_ast) + (deps (:input N8_ascii_value_printf.cpp) (glob_files_rec ../*.hpp) (universe)) + (action + (run cpp2v -v %{input} -o N8_ascii_value_printf_cpp.v --no-elaborate -- -std=c++20 -stdlib=libstdc++ ))) + (alias (name srcs) (deps N8_ascii_value_printf.cpp)) ) (subdir geeks_for_geeks_examples (rule diff --git a/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N12_area.cpp b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N12_area.cpp new file mode 100644 index 0000000..ccbab26 --- /dev/null +++ b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N12_area.cpp @@ -0,0 +1,30 @@ +// C++ program to find area +// and perimeter of rectangle +#include +using namespace std; + +// Utility function +int areaRectangle(int a, int b) +{ + int area = a * b; + return area; +} + +int perimeterRectangle(int a, int b) +{ + int perimeter = 2*(a + b); + return perimeter; +} + +// Driver code +int main() +{ + int a = 5; + int b = 6; + cout << "Area = " << + areaRectangle(a, b) << + endl; + cout << "Perimeter = " << + perimeterRectangle(a, b); + return 0; +} diff --git a/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N12_area.v b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N12_area.v new file mode 100644 index 0000000..0570fac --- /dev/null +++ b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N12_area.v @@ -0,0 +1,37 @@ +Require Import skylabs.auto.cpp.prelude.proof. +Require Import skylabs.brick.libstdcpp.test.geeks_for_geeks_examples.spec. + +Require Import skylabs.brick.libstdcpp.test.geeks_for_geeks_examples.N12_area_cpp. + +Import linearity. + +Section with_cpp. + Context `{Σ : cpp_logic, σ : genv}. + + Definition area_of_rectangle (side1 side2 : Z) := side1 * side2. + Definition perimeter_of_rectangle (side1 side2 : Z) := 2 * (side1 + side2). + Definition side1 := 5. + Definition side2 := 6. + + cpp.spec "main()" from source as main_spec with ( + \prepost{osM} _global "std::cout" |-> ostreamR 1$m osM + \pre{str} _global "std::cout" |-> ostream_contentR 1$m str + \post[Vint 0] + _global "std::cout" |-> ostream_contentR 1$m + (str ++ "Area = " ++ Z_to_string (area_of_rectangle side1 side2) ++ "\n" ++ "Perimeter = " ++ Z_to_string (perimeter_of_rectangle side1 side2)) + ). + + cpp.spec "areaRectangle(int, int)" from source inline. + cpp.spec "perimeterRectangle(int, int)" from source inline. + + Lemma main_ok : verify?[source] main_spec. + Proof. + verify_shift; go. + iExists (_ : ostreamT → ostreamT), (_ : cstring.t → cstring.t); work with br_erefl; go. + + banish_string_literals. + iModIntro. + work. + by rewrite -!(assoc_L BS.append). + Qed. +End with_cpp. diff --git a/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N0_hello_world.cpp b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N1_hello_world.cpp similarity index 100% rename from rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N0_hello_world.cpp rename to rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N1_hello_world.cpp diff --git a/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N0_hello_world.v b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N1_hello_world.v similarity index 96% rename from rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N0_hello_world.v rename to rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N1_hello_world.v index 21fd44d..2dabb26 100644 --- a/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N0_hello_world.v +++ b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N1_hello_world.v @@ -1,7 +1,7 @@ Require Import skylabs.auto.cpp.prelude.proof. Require Import skylabs.brick.libstdcpp.test.geeks_for_geeks_examples.spec. -Require Import skylabs.brick.libstdcpp.test.geeks_for_geeks_examples.N0_hello_world_cpp. +Require Import skylabs.brick.libstdcpp.test.geeks_for_geeks_examples.N1_hello_world_cpp. Section with_cpp. Context `{Σ : cpp_logic, σ : genv}. diff --git a/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N2_input.cpp b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N3_input.cpp similarity index 100% rename from rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N2_input.cpp rename to rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N3_input.cpp diff --git a/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N2_input.v b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N3_input.v similarity index 99% rename from rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N2_input.v rename to rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N3_input.v index a22b7cb..d911790 100644 --- a/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N2_input.v +++ b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N3_input.v @@ -1,7 +1,7 @@ Require Import skylabs.auto.cpp.prelude.proof. Require Import skylabs.brick.libstdcpp.test.geeks_for_geeks_examples.spec. -Require Import skylabs.brick.libstdcpp.test.geeks_for_geeks_examples.N2_input_cpp. +Require Import skylabs.brick.libstdcpp.test.geeks_for_geeks_examples.N3_input_cpp. Import linearity. diff --git a/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N4_sum.cpp b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N4_sum.cpp new file mode 100644 index 0000000..b4c759e --- /dev/null +++ b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N4_sum.cpp @@ -0,0 +1,13 @@ +// https://www.geeksforgeeks.org/cpp/cpp-add-numbers/ + +#include +using namespace std; + +int main() { + int a = 11, b = 9; + + // Adding the two numbers and printing + // their sum + cout << a + b; + return 0; +} diff --git a/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N4_sum.v b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N4_sum.v new file mode 100644 index 0000000..fd17459 --- /dev/null +++ b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N4_sum.v @@ -0,0 +1,20 @@ +Require Import skylabs.auto.cpp.prelude.proof. +Require Import skylabs.brick.libstdcpp.test.geeks_for_geeks_examples.spec. + +Require Import skylabs.brick.libstdcpp.test.geeks_for_geeks_examples.N4_sum_cpp. + +Import linearity. + +Section with_cpp. + Context `{Σ : cpp_logic, σ : genv}. + + cpp.spec "main()" from source as main_spec with ( + \prepost{osM} _global "std::cout" |-> ostreamR 1$m osM + \pre{str} _global "std::cout" |-> ostream_contentR 1$m str + \post[Vint 0] + _global "std::cout" |-> ostream_contentR 1$m (str ++ Z_to_string 20) + ). + + Lemma main_ok : verify?[source] main_spec. + Proof. verify_spec; go. Qed. +End with_cpp. diff --git a/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N4_sum_a.cpp b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N4_sum_a.cpp new file mode 100644 index 0000000..bbadd7f --- /dev/null +++ b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N4_sum_a.cpp @@ -0,0 +1,20 @@ +// https://www.geeksforgeeks.org/cpp/cpp-add-numbers/, 2nd version + +#include +using namespace std; + +int main() { + int a = 11, b = 9; + + // If b is positive, increment a to b times + for (int i = 0; i < b; i++) + a++; + + // If b is negative, decrement a to |b| times + for (int i = 0; i > b; i--) + a--; + + cout << a; + + return 0; +} diff --git a/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N4_sum_a.v b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N4_sum_a.v new file mode 100644 index 0000000..f5bad0c --- /dev/null +++ b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N4_sum_a.v @@ -0,0 +1,37 @@ +Require Import skylabs.auto.cpp.prelude.proof. +Require Import skylabs.brick.libstdcpp.test.geeks_for_geeks_examples.spec. + +Require Import skylabs.brick.libstdcpp.test.geeks_for_geeks_examples.N4_sum_a_cpp. + +Import linearity. + +Section with_cpp. + Context `{Σ : cpp_logic, σ : genv}. + + cpp.spec "main()" from source as main_spec with ( + \prepost{osM} _global "std::cout" |-> ostreamR 1$m osM + \pre{str} _global "std::cout" |-> ostream_contentR 1$m str + \post[Vint 0] + _global "std::cout" |-> ostream_contentR 1$m (str ++ Z_to_string 20) + ). + + #[global] Declare Instance Z_to_string_inj : Inj eq eq Z_to_string. + + Lemma main_ok : verify?[source] main_spec. + Proof. + verify_spec; go. + + wp_for (fun ρ => + \pre{i1} _local ρ "i" |-> intR 1$m i1 + \pre _local ρ "a" |-> intR 1$m (11 + i1) + \require 0 <= i1 <= 9 + \post* _local ρ "i" |-> anyR "int" 1$m + \post* _local ρ "a" |-> intR 1$m 20 + \post emp + ). + + go. + wp_if; go. + wp_for (fun ρ => emp); go. + Qed. +End with_cpp. diff --git a/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N5_swap.cpp b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N5_swap.cpp new file mode 100644 index 0000000..b3b635d --- /dev/null +++ b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N5_swap.cpp @@ -0,0 +1,18 @@ +// https://www.geeksforgeeks.org/cpp/cpp-program-to-swap-two-numbers/ + +#include +using namespace std; + +int main(){ + int a = 2, b = 3; + + cout << "Before swapping a = " << a << " , b = " << b << endl; + + int temp; + + temp = a; + a = b; + b = temp; + cout << "After swapping a = " << a << " , b = " << b << endl; + return 0; +} diff --git a/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N5_swap.v b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N5_swap.v new file mode 100644 index 0000000..3e02a3a --- /dev/null +++ b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N5_swap.v @@ -0,0 +1,44 @@ +Require Import skylabs.auto.cpp.prelude.proof. +Require Import skylabs.brick.libstdcpp.test.geeks_for_geeks_examples.spec. + +Require Import skylabs.brick.libstdcpp.test.geeks_for_geeks_examples.N5_swap_cpp. + +Import linearity. + +Section with_cpp. + Context `{Σ : cpp_logic, σ : genv}. + + cpp.spec "main()" from source as main_spec with ( + \prepost{osM} _global "std::cout" |-> ostreamR 1$m osM + \pre{str} _global "std::cout" |-> ostream_contentR 1$m str + \post[Vint 0] + _global "std::cout" |-> ostream_contentR 1$m + (str ++ + "Before swapping a = " ++ + Z_to_string 2 ++ " , b = " ++ Z_to_string 3 ++ "\n" ++ + "After swapping a = " ++ Z_to_string 3 ++ " , b = " ++ Z_to_string 2 ++ "\n" + ) + ). + + #[program] + Definition hint_stream_F := + \cancelx@{mpredI} + \bound_existential (stream_f : cstring.t → cstring.t) + \bound_existential (state_f : ostreamT → ostreamT) + \instantiate stream_f := fun str => (str ++ "\n")%bs + \instantiate state_f := fun osM => osM + \end. + Next Obligation. work. Qed. + + Lemma main_ok : verify?[source] main_spec. + Proof. + verify_shift; go. + (* iExists id, (fun str => str ++ "\n")%bs; go. *) + iExists (_ : ostreamT → ostreamT), (_ : cstring.t → cstring.t); work with br_erefl; go. + iExists (_ : ostreamT → ostreamT), (_ : cstring.t → cstring.t); work with br_erefl; go. + banish_string_literals. + iModIntro. + work. + by rewrite -!(assoc_L BS.append). + Qed. +End with_cpp. diff --git a/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N6_print_sizeof.cpp b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N6_print_sizeof.cpp new file mode 100644 index 0000000..8e82db0 --- /dev/null +++ b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N6_print_sizeof.cpp @@ -0,0 +1,31 @@ +#include +using namespace std; + +int main() +{ + int integerType; + char charType; + float floatType; + double doubleType; + + // Calculate and Print + // the size of integer type + cout << "Size of int is: " << sizeof(integerType) + << "\n"; + + // Calculate and Print + // the size of doubleType + cout << "Size of char is: " << sizeof(charType) << "\n"; + + // Calculate and Print + // the size of charType + cout << "Size of float is: " << sizeof(floatType) + << "\n"; + + // Calculate and Print + // the size of floatType + cout << "Size of double is: " << sizeof(doubleType) + << "\n"; + + return 0; +} diff --git a/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N6_print_sizeof.v b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N6_print_sizeof.v new file mode 100644 index 0000000..e476f45 --- /dev/null +++ b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/N6_print_sizeof.v @@ -0,0 +1,35 @@ +Require Import skylabs.auto.cpp.prelude.proof. +Require Import skylabs.brick.libstdcpp.test.geeks_for_geeks_examples.spec. + +Require Import skylabs.brick.libstdcpp.test.geeks_for_geeks_examples.N6_print_sizeof_cpp. + +Import linearity. + +Section with_cpp. + Context `{Σ : cpp_logic, σ : genv}. + + Definition newline := " +"%bs. + + cpp.spec "main()" from source as main_spec with ( + \prepost{osM} _global "std::cout" |-> ostreamR 1$m osM + \pre{str} _global "std::cout" |-> ostream_contentR 1$m str + \post[Vint 0] + _global "std::cout" |-> ostream_contentR 1$m + (str ++ + "Size of int is: " ++ Z_to_string 4 ++ newline ++ + "Size of char is: " ++ Z_to_string 1 ++ newline ++ + "Size of float is: " ++ Z_to_string 4 ++ newline ++ + "Size of double is: " ++ Z_to_string 8 ++ newline) + ). + + Lemma main_ok : verify?[source] main_spec. + Proof. + verify_shift; go. + + banish_string_literals. + iModIntro. + work. + by rewrite -!(assoc_L BS.append). + Qed. +End with_cpp. diff --git a/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/spec.v b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/spec.v index bcc48b1..32ac5d1 100644 --- a/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/spec.v +++ b/rocq-brick-libstdcpp/test/geeks_for_geeks_examples/spec.v @@ -16,19 +16,27 @@ Proof. elim: x => [|x xs /= IH] [|y1 ys1] [|y2 ys2] //= [/(inj (BS.append _))] //. Qed. +#[global] Instance BS_append_assoc : Assoc eq BS.append. +Proof. + elim => [|x xs IH] [|y ys] [|z zs] //=. all: by rewrite -IH. +Qed. + #[global] Instance refine_bs_app' (str a b : BS.t) : Refine1 true true (str ++ a = str ++ b)%bs [a = b]. Proof. tac_refine. move: H. apply: inj. Qed. +#[global] Arguments BS.append : simpl never. + Section with_cpp. Context `{Σ : cpp_logic, σ : genv}. - Parameter ostreamT : Type. - Parameter ostreamR : cQp.t -> ostreamT -> Rep. - Parameter ostream_contentR : cQp.t -> cstring.t -> Rep. + Parameter ostreamR : cQp.t -> gname -> Rep. + + (** This is effectively an <> that yields the characters and then continues *) + Parameter ostream_yield : gname -> string -> mpred -> mpred. #[global] Instance: LearnEqF1 ostreamR := ltac:(solve_learnable). - #[global] Instance: LearnEqF1 ostream_contentR := ltac:(solve_learnable). + (* #[global] Instance: LearnEqF1 ostream_contentR := ltac:(solve_learnable). *) Parameter istreamT : Type. Parameter istreamR : cQp.t -> istreamT -> Rep. @@ -36,12 +44,11 @@ Section with_cpp. cpp.spec "std::operator<<>(std::basic_ostream>&, const char*)" from source as ostream_insert_spec with ( \arg{osP} "" (Vptr osP) - \prepost{osM} osP |-> ostreamR 1$m osM - \pre{str} osP |-> ostream_contentR 1$m str + \prepost{γ} osP |-> ostreamR 1$m γ \arg{strP} "" (Vptr strP) \prepost{q__s strM} strP |-> cstring.R q__s strM - \post[Vptr osP] - osP |-> ostream_contentR 1$m (str ++ strM)). + \pre{Q} ostream_yield γ _ Q + \post[Vptr osP] Q) Parameter Z_to_string : Z -> cstring.t. #[global] Declare Instance Z_to_string_inj : Inj eq eq Z_to_string. @@ -56,4 +63,54 @@ Section with_cpp. this |-> ostream_contentR 1$m (str ++ Z_to_string n) ). + cpp.spec "std::basic_ostream>::operator<<(unsigned long)" from source as ostream_print_ulong_spec with ( + \this this + \prepost{osM} this |-> ostreamR 1$m osM + \pre{str} this |-> ostream_contentR 1$m str + \arg{n} "" (Vint n) + \post[Vptr this] + this |-> ostream_contentR 1$m (str ++ Z_to_string n) + ). + + Definition iostream_manip_spec state_f contents_f : WpSpec_cpp_val := ( + \arg{osP : ptr} "" (Vptr osP) + (* XXX: manipulators can modify [osM]! *) + \pre{osM} osP |-> ostreamR 1$m osM + \post* osP |-> ostreamR 1$m (state_f osM) + \pre{str} osP |-> ostream_contentR 1$m str + \post[Vptr osP] osP |-> ostream_contentR 1$m (contents_f str)). + + Definition ostream_cpp_type : type := + "std::basic_ostream>&". + Definition iostream_manip_kind : okind := + tFunction ostream_cpp_type [ostream_cpp_type]. + + cpp.spec "std::endl>(std::basic_ostream>&)" from source as endl_spec with ( + \exact Reduce iostream_manip_spec (fun osM => osM) (fun str => str ++ "\n")%bs + ). + + (* This is the overload taking the endl manipulator. *) + cpp.spec "std::basic_ostream>::operator<<(std::basic_ostream>&(*)(std::basic_ostream>&))" from source as ostream_insert_string_spec with ( + \this this + \arg{os_f} "" (Vptr os_f) + \pre{state_f stream_f} + os_f |-> unmaterialized_specR + iostream_manip_kind + (iostream_manip_spec state_f stream_f) + \pre{osM} this |-> ostreamR 1$m osM + \post* this |-> ostreamR 1$m (state_f osM) + \pre{str} this |-> ostream_contentR 1$m str + \post[Vptr this] + this |-> ostream_contentR 1$m (stream_f str) + ). + + Lemma ostream_contentR_aggressive (os_p : ptr) q str str': + os_p |-> ostream_contentR q str ⊢ + [| str = str' |] -∗ + os_p |-> ostream_contentR q str'. + Proof. work. Qed. + Definition ostream_contentR_aggressiveC := [CANCEL] ostream_contentR_aggressive. + End with_cpp. + +#[export] Hint Resolve ostream_contentR_aggressiveC : br_hints.