Skip to content

Commit 146715e

Browse files
committed
Add various type reflection interfaces for cppyy/numba
1 parent a727d4f commit 146715e

3 files changed

Lines changed: 186 additions & 1 deletion

File tree

include/CppInterOp/CppInterOp.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,14 @@ enum Operator : unsigned char {
9595
};
9696

9797
enum OperatorArity : unsigned char { kUnary = 1, kBinary, kBoth };
98+
enum Signedness : unsigned char { kSigned = 1, kUnsigned };
9899

99100
/// Enum modelling CVR qualifiers.
100101
enum QualKind : unsigned char {
101102
Const = 1 << 0,
102103
Volatile = 1 << 1,
103-
Restrict = 1 << 2
104+
Restrict = 1 << 2,
105+
All = Const | Volatile | Restrict
104106
};
105107

106108
/// Enum modelling programming languages.
@@ -687,6 +689,20 @@ CPPINTEROP_API bool IsRecordType(TCppType_t type);
687689
/// Checks if the provided parameter is a Plain Old Data Type (POD).
688690
CPPINTEROP_API bool IsPODType(TCppType_t type);
689691

692+
/// Checks if type has an integer representation.
693+
/// If \p s is non-null, it is set to the signedness of the type.
694+
CPPINTEROP_API bool IsIntegerType(TCppType_t type, Signedness* s = nullptr);
695+
696+
/// Checks if type has a floating representation
697+
CPPINTEROP_API bool IsFloatingType(TCppType_t type);
698+
699+
/// Checks if two types are the equivalent
700+
/// i.e. have the same canonical type
701+
CPPINTEROP_API bool IsSameType(TCppType_t type_a, TCppType_t type_b);
702+
703+
/// Checks if type is a void pointer
704+
CPPINTEROP_API bool IsVoidPointerType(TCppType_t type);
705+
690706
/// Checks if type is a pointer
691707
CPPINTEROP_API bool IsPointerType(TCppType_t type);
692708

lib/CppInterOp/CppInterOp.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2063,12 +2063,51 @@ bool IsPODType(TCppType_t type) {
20632063
return INTEROP_RETURN(QT.isPODType(getASTContext()));
20642064
}
20652065

2066+
bool IsIntegerType(TCppType_t type, Signedness* s) {
2067+
INTEROP_TRACE(type, s);
2068+
if (!type)
2069+
return INTEROP_RETURN(false);
2070+
QualType QT = QualType::getFromOpaquePtr(type);
2071+
if (!QT->hasIntegerRepresentation())
2072+
return INTEROP_RETURN(false);
2073+
if (s) {
2074+
*s = QT->hasSignedIntegerRepresentation() ? Signedness::kSigned
2075+
: Signedness::kUnsigned;
2076+
}
2077+
return INTEROP_RETURN(true);
2078+
}
2079+
2080+
bool IsFloatingType(TCppType_t type) {
2081+
INTEROP_TRACE(type);
2082+
if (!type)
2083+
return INTEROP_RETURN(false);
2084+
QualType QT = QualType::getFromOpaquePtr(type);
2085+
return INTEROP_RETURN(QT->hasFloatingRepresentation());
2086+
}
2087+
2088+
bool IsSameType(TCppType_t type_a, TCppType_t type_b) {
2089+
INTEROP_TRACE(type_a, type_b);
2090+
if (!type_a || !type_b)
2091+
return INTEROP_RETURN(false);
2092+
QualType QT1 = QualType::getFromOpaquePtr(type_a);
2093+
QualType QT2 = QualType::getFromOpaquePtr(type_b);
2094+
return INTEROP_RETURN(getASTContext().hasSameType(QT1, QT2));
2095+
}
2096+
20662097
bool IsPointerType(TCppType_t type) {
20672098
INTEROP_TRACE(type);
20682099
QualType QT = QualType::getFromOpaquePtr(type);
20692100
return INTEROP_RETURN(QT->isPointerType());
20702101
}
20712102

2103+
bool IsVoidPointerType(TCppType_t type) {
2104+
INTEROP_TRACE(type);
2105+
if (!type)
2106+
return INTEROP_RETURN(false);
2107+
QualType QT = QualType::getFromOpaquePtr(type);
2108+
return INTEROP_RETURN(QT->isVoidPointerType());
2109+
}
2110+
20722111
TCppType_t GetPointeeType(TCppType_t type) {
20732112
INTEROP_TRACE(type);
20742113
if (!IsPointerType(type))
@@ -2119,6 +2158,8 @@ TCppType_t GetNonReferenceType(TCppType_t type) {
21192158

21202159
TCppType_t GetUnderlyingType(TCppType_t type) {
21212160
INTEROP_TRACE(type);
2161+
if (!type)
2162+
return INTEROP_RETURN(nullptr);
21222163
QualType QT = QualType::getFromOpaquePtr(type);
21232164
QT = QT->getCanonicalTypeUnqualified();
21242165

unittests/CppInterOp/TypeReflectionTest.cpp

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,10 +682,138 @@ TYPED_TEST(CPPINTEROP_TEST_MODE, TypeReflection_TypeQualifiers) {
682682
EXPECT_EQ(b, Cpp::RemoveTypeQualifier(h, Cpp::QualKind::Const |
683683
Cpp::QualKind::Volatile));
684684

685+
// QualKind::All removes all qualifiers at once
686+
EXPECT_EQ(a, Cpp::RemoveTypeQualifier(h, Cpp::QualKind::All));
687+
EXPECT_EQ(a, Cpp::RemoveTypeQualifier(e, Cpp::QualKind::All));
688+
EXPECT_EQ(a, Cpp::RemoveTypeQualifier(b, Cpp::QualKind::All));
689+
// Already unqualified type is unchanged
690+
EXPECT_EQ(a, Cpp::RemoveTypeQualifier(a, Cpp::QualKind::All));
691+
685692
EXPECT_EQ(c, Cpp::AddTypeQualifier(a, Cpp::QualKind::Const));
686693
EXPECT_EQ(d, Cpp::AddTypeQualifier(a, Cpp::QualKind::Volatile));
687694
EXPECT_EQ(b, Cpp::AddTypeQualifier(a, Cpp::QualKind::Restrict));
688695
EXPECT_EQ(h, Cpp::AddTypeQualifier(a, Cpp::QualKind::Const |
689696
Cpp::QualKind::Volatile |
690697
Cpp::QualKind::Restrict));
691698
}
699+
700+
TYPED_TEST(CPPINTEROP_TEST_MODE, TypeReflection_IsIntegerType) {
701+
std::vector<Decl*> Decls;
702+
std::string code = R"(
703+
int a;
704+
int *b;
705+
double c;
706+
enum A { x, y };
707+
A evar = x;
708+
char k;
709+
long int l;
710+
unsigned int m;
711+
unsigned long n;
712+
)";
713+
714+
GetAllTopLevelDecls(code, Decls);
715+
716+
Cpp::Signedness sign;
717+
EXPECT_TRUE(Cpp::IsIntegerType(Cpp::GetVariableType(Decls[0])));
718+
EXPECT_FALSE(Cpp::IsIntegerType(Cpp::GetVariableType(Decls[1])));
719+
EXPECT_FALSE(Cpp::IsIntegerType(Cpp::GetVariableType(Decls[2])));
720+
EXPECT_TRUE(Cpp::IsIntegerType(Cpp::GetVariableType(Decls[4])));
721+
EXPECT_TRUE(Cpp::IsIntegerType(Cpp::GetVariableType(Decls[5])));
722+
EXPECT_TRUE(Cpp::IsIntegerType(Cpp::GetVariableType(Decls[6])));
723+
724+
// Check signedness via out parameter
725+
EXPECT_TRUE(Cpp::IsIntegerType(Cpp::GetVariableType(Decls[0]), &sign));
726+
EXPECT_EQ(sign, Cpp::Signedness::kSigned); // int
727+
EXPECT_TRUE(Cpp::IsIntegerType(Cpp::GetVariableType(Decls[7]), &sign));
728+
EXPECT_EQ(sign, Cpp::Signedness::kUnsigned); // unsigned int
729+
EXPECT_TRUE(Cpp::IsIntegerType(Cpp::GetVariableType(Decls[8]), &sign));
730+
EXPECT_EQ(sign, Cpp::Signedness::kUnsigned); // unsigned long
731+
}
732+
733+
TYPED_TEST(CPPINTEROP_TEST_MODE, TypeReflection_IsFloatingType) {
734+
std::vector<Decl*> Decls;
735+
std::string code = R"(
736+
float a;
737+
double b;
738+
long double c;
739+
int d;
740+
char e;
741+
)";
742+
743+
GetAllTopLevelDecls(code, Decls);
744+
745+
EXPECT_TRUE(Cpp::IsFloatingType(Cpp::GetVariableType(Decls[0])));
746+
EXPECT_TRUE(Cpp::IsFloatingType(Cpp::GetVariableType(Decls[1])));
747+
EXPECT_TRUE(Cpp::IsFloatingType(Cpp::GetVariableType(Decls[2])));
748+
EXPECT_FALSE(Cpp::IsFloatingType(Cpp::GetVariableType(Decls[3])));
749+
EXPECT_FALSE(Cpp::IsFloatingType(Cpp::GetVariableType(Decls[4])));
750+
EXPECT_FALSE(Cpp::IsFloatingType(0));
751+
}
752+
753+
TYPED_TEST(CPPINTEROP_TEST_MODE, TypeReflection_IsVoidPointerType) {
754+
std::vector<Decl*> Decls;
755+
std::string code = R"(
756+
class A {};
757+
using VoidPtrType = void*;
758+
VoidPtrType a = nullptr;
759+
void * b = nullptr;
760+
A *pa = nullptr;
761+
)";
762+
763+
GetAllTopLevelDecls(code, Decls);
764+
765+
EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetVariableType(Decls[2])),
766+
"VoidPtrType");
767+
EXPECT_TRUE(Cpp::IsVoidPointerType(Cpp::GetVariableType(Decls[2])));
768+
EXPECT_TRUE(Cpp::IsVoidPointerType(Cpp::GetVariableType(Decls[3])));
769+
EXPECT_FALSE(Cpp::IsVoidPointerType(Cpp::GetVariableType(Decls[4])));
770+
}
771+
772+
TYPED_TEST(CPPINTEROP_TEST_MODE, TypeReflection_IsSameType) {
773+
std::vector<Decl*> Decls;
774+
775+
std::string code = R"(
776+
#include <cstdarg>
777+
778+
typedef std::va_list VaListAlias;
779+
std::va_list va1;
780+
VaListAlias va2;
781+
const int ci = 0;
782+
int const ic = 0;
783+
signed int si1 = 0;
784+
int si2 = 0;
785+
void *x;
786+
)";
787+
788+
GetAllTopLevelDecls(code, Decls);
789+
ASTContext& Ctxt = Interp->getCI()->getASTContext();
790+
Decls.assign(Decls.end() - 8, Decls.end());
791+
792+
EXPECT_TRUE(
793+
Cpp::IsSameType(Cpp::GetType("bool"), Ctxt.BoolTy.getAsOpaquePtr()));
794+
EXPECT_TRUE(
795+
Cpp::IsSameType(Cpp::GetType("float"), Ctxt.FloatTy.getAsOpaquePtr()));
796+
EXPECT_TRUE(
797+
Cpp::IsSameType(Cpp::GetType("long"), Ctxt.LongTy.getAsOpaquePtr()));
798+
EXPECT_TRUE(Cpp::IsSameType(Cpp::GetType("long long"),
799+
Ctxt.LongLongTy.getAsOpaquePtr()));
800+
EXPECT_TRUE(
801+
Cpp::IsSameType(Cpp::GetType("short"), Ctxt.ShortTy.getAsOpaquePtr()));
802+
EXPECT_TRUE(
803+
Cpp::IsSameType(Cpp::GetType("char"), Ctxt.CharTy.getAsOpaquePtr()));
804+
EXPECT_TRUE(Cpp::IsSameType(Cpp::GetType("unsigned char"),
805+
Ctxt.UnsignedCharTy.getAsOpaquePtr()));
806+
EXPECT_TRUE(Cpp::IsSameType(Cpp::GetType("unsigned int"),
807+
Ctxt.UnsignedIntTy.getAsOpaquePtr()));
808+
809+
EXPECT_TRUE(Cpp::IsSameType(Cpp::GetVariableType(Decls[7]),
810+
Ctxt.VoidPtrTy.getAsOpaquePtr()));
811+
812+
// Expect the typedef to std::va_list to be the same type
813+
EXPECT_TRUE(Cpp::IsSameType(Cpp::GetVariableType(Decls[1]),
814+
Cpp::GetVariableType(Decls[2])));
815+
EXPECT_TRUE(Cpp::IsSameType(Cpp::GetVariableType(Decls[3]),
816+
Cpp::GetVariableType(Decls[4])));
817+
EXPECT_TRUE(Cpp::IsSameType(Cpp::GetVariableType(Decls[5]),
818+
Cpp::GetVariableType(Decls[6])));
819+
}

0 commit comments

Comments
 (0)