学习 LLVM(17) ContextualFoldingSet

继续上篇的 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 特化了。

转载于:https://my.oschina.net/u/232554/blog/42776

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值