Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions llvm/include/llvm/ADT/STLExtras.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Comment on lines +2619 to +2620
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get it -- how is this different than passing the lambda directly?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see, it's invoked through the conversion operator. I'd definitely focus on this aspect in the explanation of what this does, in abstract of the intended use in emplace operations

/// ```
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 {
Expand Down
11 changes: 11 additions & 0 deletions llvm/unittests/ADT/STLExtrasTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1699,4 +1699,15 @@ 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(false && "this should never be executed");
return 0;
}});
}
Comment on lines +1702 to +1711
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would benefit from tests without unordered_map.


} // namespace
Loading