llvm源码类的设计方式有些地方还是很精妙的,下面这个类有很多枚举类型,这个类真实的数据也就是Data1和Data2,Data1和Data2除了保存了两个指针之外还隐藏了一个枚举变量,这样做节省了内存,能这样做的原因是llvm::PointerIntPair<void *, 2> 里面的void*的地址值是个对齐的地址,也就是说void*的值至少是4的倍数或者4以上的数字,但是这个数字肯定是2的幂。另外void*也有另外一个精妙的地方,比如某个子类继承了CFGElement,那么要判断父类指针是那个子类,只需要根据它的Kind值判断,例如它的Kind值是Statement,那么就能找到那个子类,如果我们要取出其中的数据,比如我们知道数据在Data1里面,就可以取出其中的数据,不同子类的数据类型不一样,这个时候我们可以在各个子类里面定义一个函数比如叫 getData1() 对于A子类可能返回int*,对于B子类可能返回double*。总体来说我们从一个父类指针通过Kind找到子类,再转化为子类指针,最后获取数据。因为数据都保持在父类里,所以直接从父类转换为子类也没问题,不过需要用到引用 son s; father&f=son; f=value_father; 这样子类就从某个父类获取了数据。
class CFGElement {
public:
enum Kind {
// main kind
Statement,
Initializer,
NewAllocator,
// dtor kind
AutomaticObjectDtor,
DeleteDtor,
BaseDtor,
MemberDtor,
TemporaryDtor,
DTOR_BEGIN = AutomaticObjectDtor,
DTOR_END = TemporaryDtor
};
protected:
// The int bits are used to mark the kind.
llvm::PointerIntPair<void *, 2> Data1;
llvm::PointerIntPair<void *, 2> Data2;
CFGElement(Kind kind, const void *Ptr1, const void *Ptr2 = nullptr)
: Data1(const_cast<void*>(Ptr1), ((unsigned) kind) & 0x3),
Data2(const_cast<void*>(Ptr2), (((unsigned) kind) >> 2) & 0x3) {
assert(getKind() == kind);
}
}
llvm另外一个比较高明的设计是对于某种有静态成员类的设计。例如
class a{
public:
int a;
static int index;
}
比如有个map<int*,map<>(不一定是map,可以是其他对象)>
int*可以采用 static int index;的地址,那么我们就可以很好的管理a类对象
LLVM对类取哈希值的方式也比较特殊,对于一个类来说,其成员一般是整数,指针,字符串或者是某个子类,但是其子类的成员的类型和父类差不多
比如我们要对一个类求其哈希值,
遍历其成员
如果成员是个普通类型(整数,指针,字符串),则直接添加到Bits(Bits是FoldingSetNodeID 类的成员,这个类主要用来求哈希值)里面
如果成员是个类则进入到子类里面,遍历子类的成员,也把它们添加到Bits
最终通过FoldingSetNodeID 的成员Bits生成一个哈希值
//===--------------------------------------------------------------------===//
/// FoldingSetNodeID - This class is used to gather all the unique data bits of
/// a node. When all the bits are gathered this class is used to produce a
/// hash value for the node.
///
class FoldingSetNodeID {
/// Bits - Vector of all the data bits that make the node unique.
/// Use a SmallVector to avoid a heap allocation in the common case.
SmallVector<unsigned, 32> Bits;
public:
FoldingSetNodeID() = default;
FoldingSetNodeID(FoldingSetNodeIDRef Ref)
: Bits(Ref.getData(), Ref.getData() + Ref.getSize()) {}
/// Add* - Add various data types to Bit data.
///
void AddPointer(const void *Ptr);
void AddInteger(signed I);
void AddInteger(unsigned I);
void AddInteger(long I);
void AddInteger(unsigned long I);
void AddInteger(long long I);
void AddInteger(unsigned long long I);
void AddBoolean(bool B) { AddInteger(B ? 1U : 0U); }
void AddString(StringRef String);
void AddNodeID(const FoldingSetNodeID &ID);
}
另外一种比较有意思的设计是,就是通过模板可以知道子类的类型
template <typename DERIVED>
class ClusterAnalysis {
}