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

Victor Chernyakin via llvm-commits llvm-commits at lists.llvm.org
Sat Dec 6 20:00:14 PST 2025


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

>From d48726524e0d6a36bfa1cfc4a4669dcaeb8d0f6c Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Sat, 6 Dec 2025 19:43:31 -0800
Subject: [PATCH] [LLVM] Add helper class for working with caches

---
 llvm/include/llvm/ADT/STLExtras.h    | 24 ++++++++++++++++++++++++
 llvm/unittests/ADT/STLExtrasTest.cpp |  9 +++++++++
 2 files changed, 33 insertions(+)

diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h
index af0e4a36be1b1..96b0967317547 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 &&F LLVM_LIFETIME_BOUND) : Fn(std::forward<FnT>(F)) {}
+
+  template <typename T> constexpr operator T() {
+    return std::forward<FnT>(Fn)();
+  }
+
+private:
+  FnT &&Fn;
+};
+
+// Silence -Wctad-maybe-unsupported.
+template <typename FnT> defer(FnT &&) -> 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



More information about the llvm-commits mailing list