Skip to content

Commit 2dd8a7c

Browse files
committed
[ADT] Introduce a static_cast_to
1 parent b7e922a commit 2dd8a7c

File tree

2 files changed

+100
-0
lines changed

2 files changed

+100
-0
lines changed

llvm/include/llvm/Support/Casting.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,42 @@ template <typename... Types> struct IsaAndPresentCheckPredicate {
816816
return isa_and_present<Types...>(Val);
817817
}
818818
};
819+
820+
//===----------------------------------------------------------------------===//
821+
// Casting Function Objects
822+
//===----------------------------------------------------------------------===//
823+
824+
/// Usable in generic algorithms like map_range
825+
template <typename U> struct StaticCastFunc {
826+
template <typename T> decltype(auto) operator()(const T &Val) const {
827+
return static_cast<U>(Val);
828+
}
829+
};
830+
831+
template <typename U> struct DynCastFunc {
832+
template <typename T> decltype(auto) operator()(const T &Val) const {
833+
return dyn_cast<U>(Val);
834+
}
835+
};
836+
837+
template <typename U> struct CastFunc {
838+
template <typename T> decltype(auto) operator()(const T &Val) const {
839+
return cast<U>(Val);
840+
}
841+
};
842+
843+
template <typename U> struct CastIfPresentFunc {
844+
template <typename T> decltype(auto) operator()(const T &Val) const {
845+
return cast_if_present<U>(Val);
846+
}
847+
};
848+
849+
template <typename U> struct DynCastIfPresentFunc {
850+
template <typename T> decltype(auto) operator()(const T &Val) const {
851+
return dyn_cast_if_present<U>(Val);
852+
}
853+
};
854+
819855
} // namespace detail
820856

821857
/// Function object wrapper for the `llvm::isa` type check. The function call
@@ -841,6 +877,22 @@ template <typename... Types>
841877
inline constexpr detail::IsaAndPresentCheckPredicate<Types...>
842878
IsaAndPresentPred{};
843879

880+
/// Function objects corresponding to the Cast types defined above.
881+
template <typename... Types>
882+
inline constexpr detail::StaticCastFunc<Types...> StaticCastTo{};
883+
884+
template <typename... Types>
885+
inline constexpr detail::CastFunc<Types...> CastTo{};
886+
887+
template <typename... Types>
888+
inline constexpr detail::CastIfPresentFunc<Types...> CastIfPresentTo{};
889+
890+
template <typename... Types>
891+
inline constexpr detail::DynCastIfPresentFunc<Types...> DynCastIfPresentTo{};
892+
893+
template <typename... Types>
894+
inline constexpr detail::DynCastFunc<Types...> DynCastTo{};
895+
844896
} // end namespace llvm
845897

846898
#endif // LLVM_SUPPORT_CASTING_H

llvm/unittests/Support/Casting.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "llvm/Support/Casting.h"
10+
#include "llvm/ADT/STLExtras.h"
1011
#include "llvm/IR/User.h"
1112
#include "llvm/Support/Debug.h"
1213
#include "llvm/Support/raw_ostream.h"
@@ -561,6 +562,53 @@ TEST(CastingTest, assertion_check_unique_ptr) {
561562
<< "Invalid cast of const ref did not cause an abort()";
562563
}
563564

565+
TEST(Casting, StaticCastPredicate) {
566+
std::vector<uint32_t> Values{1, 2};
567+
568+
EXPECT_TRUE(
569+
all_of(map_range(Values, StaticCastTo<uint64_t>),
570+
[](const auto &V) { return sizeof(V) == sizeof(uint64_t); }));
571+
}
572+
573+
TEST(Casting, LLVMRTTIPredicates) {
574+
struct Base {
575+
enum Kind { BK_Base, BK_Derived };
576+
const Kind K;
577+
Base(Kind K = BK_Base) : K(K) {}
578+
Kind getKind() const { return K; }
579+
virtual ~Base() = default;
580+
};
581+
582+
struct Derived : public Base {
583+
Derived() : Base(BK_Derived) {}
584+
static bool classof(const Base *B) { return B->getKind() == BK_Derived; }
585+
};
586+
587+
Base B;
588+
Derived D;
589+
590+
std::vector<Base *> RTTI{&B, &D, nullptr};
591+
auto NonNull = drop_end(RTTI);
592+
auto OnlyDerived = drop_begin(NonNull);
593+
auto Casted = map_range(OnlyDerived, CastTo<Derived>);
594+
auto DynCasted = map_range(NonNull, DynCastTo<Derived>);
595+
auto DynCastedIfPresent = map_range(RTTI, DynCastIfPresentTo<Derived>);
596+
auto CastedIfPresent = map_range(drop_begin(RTTI), CastIfPresentTo<Derived>);
597+
598+
auto Same = [](const auto &T) {
599+
const auto &[A, B] = T;
600+
return A == B;
601+
};
602+
EXPECT_TRUE(all_of(zip_longest(Casted, std::vector<Derived *>{&D}), Same));
603+
EXPECT_TRUE(all_of(
604+
zip_longest(DynCasted, std::vector<Derived *>{nullptr, &D}), Same));
605+
EXPECT_TRUE(all_of(zip_longest(DynCastedIfPresent,
606+
std::vector<Derived *>{nullptr, &D, nullptr}),
607+
Same));
608+
EXPECT_TRUE(all_of(
609+
zip_longest(CastedIfPresent, std::vector<Derived *>{&D, nullptr}), Same));
610+
}
611+
564612
} // end namespace assertion_checks
565613
#endif
566614
} // end namespace

0 commit comments

Comments
 (0)