今天来学习一下PointerUnion类,它的作用是可以存几种类型指针中的一种。
/// PointerUnion P;
/// P = (int*)0;
/// printf("%d %d", P.is(), P.is()); //
prints "1 0"
/// X = P.get(); // ok.
/// Y = P.get(); // runtime assertion
failure.
/// Z = P.get(); // compile time
failure.
/// P = (float*)0;
/// Y = P.get(); // ok.
/// X = P.get(); // runtime assertion
failure.
它通过
/// Test if the Union currently holds the type matching T.
template bool is() const {
constexpr int Index =
pointer_union_detail::TypeIndex::Index;
static_assert(Index < sizeof...(PTs),
"PointerUnion::is given type not in the
union");
return this->Val.getInt() ==
Index;
}
/// Returns the value of the specified pointer type.
///
/// If the specified pointer type is incorrect, assert.
template T get() const {
assert(is() && "Invalid
accessor called");
return
PointerLikeTypeTraits::getFromVoidPointer(this->Val.getPointer());
}
中的static_assert来让Z = P.get()报错。
/// Find the index of a type in a list of types.
TypeIndex::Index
/// is the index of T in Us, or sizeof...(Us) if T does not
appear in the
/// list.
template struct TypeIndex;
template struct TypeIndex {
static constexpr int Index = 0;
};
template
struct TypeIndex {
static constexpr int Index = 1 +
TypeIndex::Index;
};
template struct TypeIndex {
static constexpr int Index = 0;
};
这个类返回某个类在多类中的序号。
sizeof...(PTs)这个应该返回了多个类的个数。
所以当放一个int*的时候会把序号0存进上一讲提到的PointerIntPair,
并且is()方法会判断调用的时候的参数序号是否与所存相同。
这个类不能改值。存进去就不能改了。
template
class PointerUnion
: public
pointer_union_detail::PointerUnionMembers<</p>
PointerUnion,
PointerIntPair<</p>
void *, pointer_union_detail::bitsRequired(sizeof...(PTs)),
int,
pointer_union_detail::PointerUnionUIntTraits>,
0, PTs...> {
这个类从PointerUnionMembers继承。
PointerUnionMembers这个类挺有意思的。它自己继承自己。然后一个接一个。第一个序号0(第三个Int
I参数)
然后这时候是最全参数,之前一直找不到四个参数的实现,其实这个PTs...相当于把int*和float*展开。
是对应的五个参数的实现,然后它继承四个参数的实现。
接着它使用
template
typename ...Types>
class PointerUnionMembers
: public PointerUnionMembers {
using Base = PointerUnionMembers;
public:
using Base::Base;
在第二层的时候把Int*给剥离出来。
所以第二层的类型从
llvm::pointer_union_detail::PointerUnionMembers,
llvm::PointerIntPair, llvm::PointerIntPairInfo >
>, 0, int *, float *> * 0x103a04100
0x0000000103a04100
变为
llvm::pointer_union_detail::PointerUnionMembers,
llvm::PointerIntPair, llvm::PointerIntPairInfo >
>, 1, float *>
最内层是
llvm::pointer_union_detail::PointerUnionMembers,
llvm::PointerIntPair, llvm::PointerIntPairInfo >
>, 2>
template
class PointerUnionMembers {
protected:
ValTy Val;
PointerUnionMembers() = default;
PointerUnionMembers(ValTy Val) : Val(Val) {}
friend struct PointerLikeTypeTraits;
};
这个最里面才是PointerIntPair对象,也就是不管多少层,最后只有一个PointerIntPair对像,也只有一个序号和它对应。
/// Provide PointerLikeTypeTraits for void* that is used by
PointerUnion
/// for the template arguments.
template class PointerUnionUIntTraits {
public:
static inline void *getAsVoidPointer(void *P) { return P;
}
static inline void *getFromVoidPointer(void *P) { return
P; }
static constexpr int NumLowBitsAvailable =
lowBitsAvailable();
};
template constexpr int lowBitsAvailable() {
return
std::min({PointerLikeTypeTraits::NumLowBitsAvailable...});
}
下面模板做了特化。
// Teach SmallPtrSet that PointerUnion is "basically a
pointer", that has
// # low bits available =
min(PT1bits,PT2bits)-1.
template
struct PointerLikeTypeTraits> {
static inline void *getAsVoidPointer(const PointerUnion
&P) {
return P.getOpaqueValue();
}
static inline PointerUnion getFromVoidPointer(void *P) {
return PointerUnion::getFromOpaqueValue(P);
}
// The number of bits available are the min of the pointer types
minus the
// bits needed for the discriminator.
static constexpr int NumLowBitsAvailable =
PointerLikeTypeTraits
PointerUnion::Val)>::NumLowBitsAvailable;
};
指针个数需要的bit,不能超过其中最小类型的alignof.
PointerUnion poe(&mei);直接报错
PointerUnion poe(&mei);可以
PointerUnion poe(&mei);
报错,因为alignof(short)=2 而当有3个参数时,它需要2位。
template
struct PointerIntPairInfo {
static_assert(PtrTraits::NumLowBitsAvailable
<</p>
std::numeric_limits::digits,
"cannot use a pointer type that has all bits
free");
static_assert(IntBits <=
PtrTraits::NumLowBitsAvailable,
"PointerIntPair with integer size too large for
pointer");
IntBits = 2就已经冲突了。
In file included from
/Users/conanchen/llvm-project/llvm/unittests/ADT/PointerUnionTest.cpp:9:
In file included from
/Users/conanchen/llvm-project/llvm/include/llvm/ADT/PointerUnion.h:18:
/Users/conanchen/llvm-project/llvm/include/llvm/ADT/PointerIntPair.h:148:3:
error: static_assert failed due to requirement '2U
<=
PointerUnionUIntTraits::NumLowBitsAvailable'
"PointerIntPair with integer size too large for
pointer"
static_assert(IntBits <=
PtrTraits::NumLowBitsAvailable,
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LLVM源码阅读之三---PointerUnion
今天来学习一下PointerUnion类,它的作用是可以存几种类型指针中的一种。
/// PointerUnion P;
/// P = (int*)0;
/// printf("%d %d", P.is(), P.is()); // prints "1 0"
/// X = P.get(); // ok.
/// Y = P.get(); // runtime assertion failure.
/// Z = P.get(); // compile time failure.
/// P = (float*)0;
/// Y = P.get(); // ok.
/// X = P.get(); // runtime assertion failure.
它通过
/// Test if the Union currently holds the type matching T.
template bool is() const {
constexpr int Index = pointer_union_detail::TypeIndex::Index;
static_assert(Index < sizeof...(PTs),
"PointerUnion::is given type not in the union");
return this->Val.getInt() == Index;
}
/// Returns the value of the specified pointer type.
///
/// If the specified pointer type is incorrect, assert.
template T get() const {
assert(is() && "Invalid accessor called");
return PointerLikeTypeTraits::getFromVoidPointer(this->Val.getPointer());
}
中的static_assert来让Z = P.get()报错。
/// Find the index of a type in a list of types. TypeIndex::Index
/// is the index of T in Us, or sizeof...(Us) if T does not appear in the
/// list.
template struct TypeIndex;
template struct TypeIndex {
static constexpr int Index = 0;
};
template
struct TypeIndex {
static constexpr int Index = 1 + TypeIndex::Index;
};
template struct TypeIndex {
static constexpr int Index = 0;
};
这个类返回某个类在多类中的序号。
sizeof...(PTs)这个应该返回了多个类的个数。
所以当放一个int*的时候会把序号0存进上一讲提到的PointerIntPair, 并且is()方法会判断调用的时候的参数序号是否与所存相同。
这个类不能改值。存进去就不能改了。
template
class PointerUnion
: public pointer_union_detail::PointerUnionMembers<</p>
PointerUnion,
PointerIntPair<</p>
void *, pointer_union_detail::bitsRequired(sizeof...(PTs)), int,
pointer_union_detail::PointerUnionUIntTraits>,
0, PTs...> {
这个类从PointerUnionMembers继承。
PointerUnionMembers这个类挺有意思的。它自己继承自己。然后一个接一个。第一个序号0(第三个Int I参数)
然后这时候是最全参数,之前一直找不到四个参数的实现,其实这个PTs...相当于把int*和float*展开。
是对应的五个参数的实现,然后它继承四个参数的实现。
接着它使用
template
typename ...Types>
class PointerUnionMembers
: public PointerUnionMembers {
using Base = PointerUnionMembers;
public:
using Base::Base;
在第二层的时候把Int*给剥离出来。
所以第二层的类型从
llvm::pointer_union_detail::PointerUnionMembers, llvm::PointerIntPair, llvm::PointerIntPairInfo > >, 0, int *, float *> * 0x103a04100 0x0000000103a04100
变为
llvm::pointer_union_detail::PointerUnionMembers, llvm::PointerIntPair, llvm::PointerIntPairInfo > >, 1, float *>
最内层是
llvm::pointer_union_detail::PointerUnionMembers, llvm::PointerIntPair, llvm::PointerIntPairInfo > >, 2>
template
class PointerUnionMembers {
protected:
ValTy Val;
PointerUnionMembers() = default;
PointerUnionMembers(ValTy Val) : Val(Val) {}
friend struct PointerLikeTypeTraits;
};
这个最里面才是PointerIntPair对象,也就是不管多少层,最后只有一个PointerIntPair对像,也只有一个序号和它对应。
/// Provide PointerLikeTypeTraits for void* that is used by PointerUnion
/// for the template arguments.
template class PointerUnionUIntTraits {
public:
static inline void *getAsVoidPointer(void *P) { return P; }
static inline void *getFromVoidPointer(void *P) { return P; }
static constexpr int NumLowBitsAvailable = lowBitsAvailable();
};
template constexpr int lowBitsAvailable() {
return std::min({PointerLikeTypeTraits::NumLowBitsAvailable...});
}
下面模板做了特化。
// Teach SmallPtrSet that PointerUnion is "basically a pointer", that has
// # low bits available = min(PT1bits,PT2bits)-1.
template
struct PointerLikeTypeTraits> {
static inline void *getAsVoidPointer(const PointerUnion &P) {
return P.getOpaqueValue();
}
static inline PointerUnion getFromVoidPointer(void *P) {
return PointerUnion::getFromOpaqueValue(P);
}
// The number of bits available are the min of the pointer types minus the
// bits needed for the discriminator.
static constexpr int NumLowBitsAvailable = PointerLikeTypeTraits
PointerUnion::Val)>::NumLowBitsAvailable;
};
指针个数需要的bit,不能超过其中最小类型的alignof.
PointerUnion poe(&mei);直接报错
PointerUnion poe(&mei);可以
PointerUnion poe(&mei);
报错,因为alignof(short)=2 而当有3个参数时,它需要2位。
template
struct PointerIntPairInfo {
static_assert(PtrTraits::NumLowBitsAvailable <</p>
std::numeric_limits::digits,
"cannot use a pointer type that has all bits free");
static_assert(IntBits <= PtrTraits::NumLowBitsAvailable,
"PointerIntPair with integer size too large for pointer");
IntBits = 2就已经冲突了。
In file included from /Users/conanchen/llvm-project/llvm/unittests/ADT/PointerUnionTest.cpp:9:
In file included from /Users/conanchen/llvm-project/llvm/include/llvm/ADT/PointerUnion.h:18:
/Users/conanchen/llvm-project/llvm/include/llvm/ADT/PointerIntPair.h:148:3: error: static_assert failed due to requirement '2U <= PointerUnionUIntTraits::NumLowBitsAvailable' "PointerIntPair with integer size too large for pointer"
static_assert(IntBits <= PtrTraits::NumLowBitsAvailable,
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~