您的位置:首页 > 其它

学习 LLVM(17) ContextualFoldingSet

2012-03-07 00:00 239 查看
继续上篇的 FoldingSet 学习。

== ContextualFoldingSet ==
ContextualFoldingSet 模板类提供对 FoldingSet 的一些改进,其在调用 Profile() 等方法的时候提供一个 context(上下文、环境) 参数。模板类 T 必须继承自 FoldingSetNode,并实现 Profile(ID, Ctx) 签名的方法。

类概要如下:
<syntaxhighlight lang="cpp">
template<T, CTXT>
class ContextualFoldingSet : public FoldingSetImpl {
// 原注释称不能从 FoldingSet<> 继承,因为里面的 Profile 函数没有 ctxt 参数。
CTXT Context; // 此 FoldingSet 对应的环境,构造的时候初始化。

// 重载基类方法,实现带 Context 参数的 Profile() 方法调用。
virtual GetNodeProfile(Node *, ID)
virtual NodeEquals() // 实现为带 ctx 参数的 Equals() 调用
virtual ComputeNodeHash() // 实现为带 ctx 参数的 ComputeHash() 调用。

this(ctx, initS) // 构造函数,使用指定环境和初始尺寸。
iterator, bucket_iterator 等的定义
begin(),end(),bucket_begin(),bucket_end() 等迭代器实现

GetOrInsertNode(),FindNodeOrInsertPos() 同 FoldingSet
}
</syntaxhighlight>

* 注1:构造函数实现中要求 CTXT 类实现复制构造语义。
* 注2:FoldingSet, ContextualFoldingSet 提供两种迭代器,对 Node 的 iterator,对 bucket 内的节点遍历的 bucket_iterator。这和其内部使用的数据结构有关。问题是,提供的 bucket_iterator 在什么地方用呢?为什么要用呢?

这个类在内部多了一个 Context(上下文,环境),并在 Profile(), Equals(), ComputeHash() 调用中都带有此参数。比起 FoldingSet 可能适用范围更广一些。

也许因为 FoldingSetImpl 有两个子类:FoldingSet, ContextualFoldingSet,因此使用了 virtual 的析构、GetNodeProfile() 等方法让子类重载。如果使用模板也许会导致代码太大?

== FoldingSetIteratorImpl ==
这个类用于实现 FoldingSet 中节点(Node)的迭代器。

实现的核心是 advance() 方法,当在 Node 链的时候,向后查找;否则找下一个有节点的桶。
这与 FoldingSet 中使用的数据结构相关。这里不详细说明了。

== FoldingSetIterator ==
模板类 FoldingSetIterator<T> 从 FoldingSetIteratorImpl 继承,提供构造,*, ->, ++, ++(int) 的实现。

其实现为一个 forward_iterator.

== FoldingSetBucketIteratorImpl ==
这个类提供公共的 bucket 桶内节点链表的迭代器基类。其能够遍历 foldingset 哈希表中的桶内节点。提供了两种构造,估计是为了支持 begin(), end() 的实现(参见 FoldingSet 中的代码)。

核心方法是 advance(),其遍历其下一个节点指针(getNextInBucket())。

== FoldingSetBucketIterator ==
类似于 FoldingSetIterator。从 FoldingSetBucketIteratorImpl 继承,提供构造,*, ->, ++, ++(int) 实现。

== FoldingSetNodeWrapper ==
FoldingSetNodeWrapper 类用于"包装"(warp)任意类型,使其能够插入到 FoldingSet 中。

<syntaxhighlight lang="cpp">
template<T> class FoldingSetNodeWrapper : public FoldingSetNode {
T data; // 数据包装进来。

this(const T&) // 构造函数,需要 T 实现复制构造语义。
virtual ~this() // 虚析构。为什么?
template<A1,[A2,A3,A4...]>this(A1&[,A2&,A3&,A4&...]) // 多种形态的构造,方便 data 的不同构造方式。

Profile(ID) // 实现对 data 的 ID 信息生成。
getValue(), T&() // 获取 data 的方法。
}
</syntaxhighlight>

将 T data 封装起来,通过特化 FoldingSetTrait<T> 提供 Profile() 方法外部的实现,这样不用 T 实现 Profile() 方法(也许 T 是别人写的,其没有 Profile 方法)。

== FastFoldingSetNode ==
类 FastFoldingSetNode 是 FoldingSetNode 的子类,其保存(缓存) FoldingSetNodeID 的值,这样不用每次都调用 Profile 方法去计算。此方式是空间换时间,对于 ID 很长生成成本高的时候有用,因而也允许节点释放掉那些不需要产生 ID 的那些信息(字段、数据)。

然而在实现的 Profile() 函数中,采用的 ID.AddNodeID() 方法,仍然将整个 ID 内容复制了一份,也许应该有更好的办法?例如引用而非复制?

== FoldingSetTrait<T*> ==
这是对 FoldingSetTrait 的特化,适合于指针类型。实现的 Profile() 方法实际为:
ID.AddPointer(T*)
也即在 ID 中只存在一个指针。一般不用为每种指针特定实现 Trait 特化了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  LLVM