From 1ea4a2d2a39204ba31598117a304c8b173b86322 Mon Sep 17 00:00:00 2001 From: Victor Chernyakin 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 | 11 +++++++++++ 2 files changed, 35 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 using has_sizeof = decltype(sizeof(T)); template constexpr bool is_incomplete_v = !is_detected::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 Cache; +/// auto& Value = Cache.try_emplace( +/// Key, llvm::defer {[] { /* heavy work */ }}).first->second; +/// ``` +template class defer { +public: + constexpr defer(FnT &&F LLVM_LIFETIME_BOUND) : Fn(std::forward(F)) {} + + template constexpr operator T() { + return std::forward(Fn)(); + } + +private: + FnT &&Fn; +}; + +// Silence -Wctad-maybe-unsupported. +template defer(FnT &&) -> defer; + } // end namespace llvm namespace std { diff --git a/llvm/unittests/ADT/STLExtrasTest.cpp b/llvm/unittests/ADT/STLExtrasTest.cpp index 85567775e4ebd..15237f8b32f13 100644 --- a/llvm/unittests/ADT/STLExtrasTest.cpp +++ b/llvm/unittests/ADT/STLExtrasTest.cpp @@ -1699,4 +1699,15 @@ struct Bar {}; static_assert(is_incomplete_v, "Foo is incomplete"); static_assert(!is_incomplete_v, "Bar is defined"); +TEST(STLExtrasTest, Defer) { + std::unordered_map 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(false && "this should never be executed"); + return 0; + }}); +} + } // namespace