[llvm] [LLVM] Add helper class for working with caches (PR #171008)

via llvm-commits llvm-commits at lists.llvm.org
Sat Dec 6 19:57:03 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-adt

Author: Victor Chernyakin (localspook)

<details>
<summary>Changes</summary>

See the doc comment for what it does.

I'm planning to use this in an upcoming refactor of [this function](https://github.com/llvm/llvm-project/blob/315c904e3e1c00ea1ec7f0757e4c538ec2513624/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp#L65). Here's [another, completely unrelated function](https://github.com/llvm/llvm-project/blob/315c904e3e1c00ea1ec7f0757e4c538ec2513624/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp#L253) it could simplify; this seems like a generally useful feature.

---
Full diff: https://github.com/llvm/llvm-project/pull/171008.diff


2 Files Affected:

- (modified) llvm/include/llvm/ADT/STLExtras.h (+24) 
- (modified) llvm/unittests/ADT/STLExtrasTest.cpp (+9) 


``````````diff
diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h
index af0e4a36be1b1..4645b35b234fb 100644
--- a/llvm/include/llvm/ADT/STLExtras.h
+++ b/llvm/include/llvm/ADT/STLExtras.h
@@ -2610,6 +2610,30 @@ template <typename T> using has_sizeof = decltype(sizeof(T));
 template <typename T>
 constexpr bool is_incomplete_v = !is_detected<detail::has_sizeof, T>::value;
 
+/// A utility for working with maps that allows concisely expressing "perform
+/// and cache this expensive computation only if it isn't already cached".
+/// Use it like so:
+///
+/// ```cpp
+/// std::unordered_map<K, V> Cache;
+/// auto& Value = Cache.try_emplace(
+///     Key, llvm::defer {[] { /* heavy work */ }}).first->second;
+/// ```
+template <typename FnT> class defer {
+public:
+  constexpr defer(FnT &&Fn LLVM_LIFETIME_BOUND) : Fn(Fn) {}
+
+  template <typename U> constexpr operator U() {
+    return std::forward<FnT>(Fn)();
+  }
+
+private:
+  FnT &Fn;
+};
+
+// Silence -Wctad-maybe-unsupported.
+template <typename FnT> defer(FnT &&Fn LLVM_LIFETIME_BOUND) -> defer<FnT>;
+
 } // end namespace llvm
 
 namespace std {
diff --git a/llvm/unittests/ADT/STLExtrasTest.cpp b/llvm/unittests/ADT/STLExtrasTest.cpp
index 85567775e4ebd..18a78e625022c 100644
--- a/llvm/unittests/ADT/STLExtrasTest.cpp
+++ b/llvm/unittests/ADT/STLExtrasTest.cpp
@@ -1699,4 +1699,13 @@ struct Bar {};
 static_assert(is_incomplete_v<Foo>, "Foo is incomplete");
 static_assert(!is_incomplete_v<Bar>, "Bar is defined");
 
+TEST(STLExtrasTest, Defer) {
+  std::unordered_map<int, int> Cache;
+  const auto [It, Inserted]{Cache.try_emplace(1, defer{[] { return 10; }})};
+  ASSERT_TRUE(Inserted);
+  ASSERT_EQ(It->second, 10);
+  Cache.try_emplace(
+      1, defer{[] { ASSERT_TRUE(false && "this should never be executed"); }});
+}
+
 } // namespace

``````````

</details>


https://github.com/llvm/llvm-project/pull/171008


More information about the llvm-commits mailing list