Skip to content

Commit b403ec8

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

File tree

2 files changed

+98
-0
lines changed

2 files changed

+98
-0
lines changed

llvm/include/llvm/Support/Casting.h

Lines changed: 50 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()(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()(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()(T &&Val) const {
839+
return cast<U>(Val);
840+
}
841+
};
842+
843+
template <typename U> struct CastIfPresentFunc {
844+
template <typename T> decltype(auto) operator()(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()(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,20 @@ 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 From> inline constexpr detail::CastFunc<From> CastTo{};
885+
886+
template <typename From>
887+
inline constexpr detail::CastIfPresentFunc<From> CastIfPresentTo{};
888+
889+
template <typename From>
890+
inline constexpr detail::DynCastIfPresentFunc<From> DynCastIfPresentTo{};
891+
892+
template <typename From> inline constexpr detail::DynCastFunc<From> DynCastTo{};
893+
844894
} // end namespace llvm
845895

846896
#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,9 +7,11 @@
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"
14+
#include "gmock/gmock.h"
1315
#include "gtest/gtest.h"
1416
#include <cstdlib>
1517

@@ -561,6 +563,52 @@ TEST(CastingTest, assertion_check_unique_ptr) {
561563
<< "Invalid cast of const ref did not cause an abort()";
562564
}
563565

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

0 commit comments

Comments
 (0)