diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 741c4267..b723bfe9 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -152,37 +152,6 @@ }, "selectedYankedVersions": {}, "moduleExtensions": { - "@@apple_support+//crosstool:setup.bzl%apple_cc_configure_extension": { - "general": { - "bzlTransitiveDigest": "E970FlMbwpgJPdPUQzatKh6BMfeE0ZpWABvwshh7Tmg=", - "usagesDigest": "aYRVMk+1OupIp+5hdBlpzT36qgd6ntgSxYTzMLW5K4U=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "local_config_apple_cc_toolchains": { - "repoRuleId": "@@apple_support+//crosstool:setup.bzl%_apple_cc_autoconf_toolchains", - "attributes": {} - }, - "local_config_apple_cc": { - "repoRuleId": "@@apple_support+//crosstool:setup.bzl%_apple_cc_autoconf", - "attributes": {} - } - }, - "recordedRepoMappingEntries": [ - [ - "apple_support+", - "bazel_tools", - "bazel_tools" - ], - [ - "bazel_tools", - "rules_cc", - "rules_cc+" - ] - ] - } - }, "@@rules_fuzzing+//fuzzing/private:extensions.bzl%non_module_dependencies": { "general": { "bzlTransitiveDigest": "mGiTB79hRNjmeDTQdzkpCHyzXhErMbufeAmySBt7s5s=", @@ -268,7 +237,7 @@ }, "@@rules_kotlin+//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": { "general": { - "bzlTransitiveDigest": "hUTp2w+RUVdL7ma5esCXZJAFnX7vLbVfLd7FwnQI6bU=", + "bzlTransitiveDigest": "OlvsB0HsvxbR8ZN+J9Vf00X/+WVz/Y/5Xrq2LgcVfdo=", "usagesDigest": "QI2z8ZUR+mqtbwsf2fLqYdJAkPOHdOV+tF2yVAUgRzw=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, diff --git a/exploration/BUILD.bazel b/exploration/BUILD.bazel index 37ae3622..cbc98888 100644 --- a/exploration/BUILD.bazel +++ b/exploration/BUILD.bazel @@ -33,3 +33,12 @@ build_test( name = "traits_and_concepts_build_test", targets = ["traits_and_concepts"], ) + +cc_test( + name = "reference_wrappers_test", + srcs = ["reference_wrappers_test.cc"], + deps = [ + "//:indirect", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/exploration/reference_wrappers_test.cc b/exploration/reference_wrappers_test.cc new file mode 100644 index 00000000..79940edb --- /dev/null +++ b/exploration/reference_wrappers_test.cc @@ -0,0 +1,82 @@ +#include + +#include + +#include "indirect.h" + +namespace { + +TEST(IndirectExploration, ReferenceWrapperAndSwap) { + // Given two dynamically allocated values managed with `indirect`. + auto a = xyz::indirect(3); + auto b = xyz::indirect(4); + + // Values are as expected. + EXPECT_EQ(*a, 3); + EXPECT_EQ(*b, 4); + + // Given references to the values. + auto ar = std::ref(*a); + auto br = std::ref(*b); + + // Values accessed through the references are as expected. + EXPECT_EQ(ar, 3); + EXPECT_EQ(br, 4); + + // When we swap the two indirect values. + swap(a, b); + // Then the values themselves have been swapped. + EXPECT_EQ(*a, 4); + EXPECT_EQ(*b, 3); + + // But the reference values refer to the original values. + EXPECT_EQ(ar, 3); + EXPECT_EQ(br, 4); + + // When we swap the two reference wrappers. + swap(ar, br); + + // Then the values accessed through references have been swapped. + EXPECT_EQ(ar, 4); + EXPECT_EQ(br, 3); +} + +TEST(IndirectExploration, ReferenceWrapperAndMove) { + // Given two dynamically allocated values managed with `indirect`. + auto a = xyz::indirect(3); + auto b = xyz::indirect(4); + + // Values are as expected. + EXPECT_EQ(*a, 3); + EXPECT_EQ(*b, 4); + + // Given references to the values. + auto ar = std::ref(*a); + auto br = std::ref(*b); + + // Values accessed through the references are as expected. + EXPECT_EQ(ar, 3); + EXPECT_EQ(br, 4); + + // When we move values and references. + a = std::move(b); // this renders `b` valueless. + + // Note: At this point ar is a reference to a value which no longer exists. + // EXPECT_EQ(ar, 3); - This would lead to heap-use-after-free when run under + // ASAN. + + ar = std::move(br); // this does nothing to `br`. + + // The moved-from indirect is valueless. + EXPECT_TRUE(b.valueless_after_move()); + // b-ref refers to the value it referred to before the move. + EXPECT_EQ(br, 4); // observing the lvalue via operator int&(). + // Perhaps this is surprising?? + + // The `a` indirect and `a` reference-wrapper now refer to the moved-from + // value. + EXPECT_EQ(*a, 4); + EXPECT_EQ(ar, 4); // observing the lvalue via operator int&() +} + +} // namespace