学习 LLVM(11) iplist 和 ilist

梦想与她 提交于 2020-02-29 13:51:15

位于 llvm/include/llvm/[[ADT]]/[[ilist.h]]

参见:
* http://llvm.org/docs/ProgrammersManual.html#dss_ilist
* [[ilist.h]], [[ilist]]
* intrusive -- 侵入的、贯入的、打扰的、闯入的。

== 简介 ==
ilist/iplist 被称为是侵入式的(intrusive),原因在于它要求其模板参数类 T 里面提供有 next/prev 指针,并且实现 getNext(), setNext(), getPrev(), setPrev() 的函数。

ilist_iterator 模板类用于实现 ilist/iplist 的遍历。

其实现可看做是一个典型的 std list 容器类。参见 std。

<B>缺点</B>:需要 T 提供缺省构造,用于产生哨兵(sentinel)节点,及提供 getNext(), getPrev() 等函数用于访问 prev/next 节点。

iplist - list 容器的子集。可用于多态类,也即有一个公共基类 其保存 next/prev 指针。ilist 自身只是保存了一个链表 list 的头指针。

== 类概要 ==
<syntaxhighlight lang="cpp">
template<typename NodeTy, typename Traits=ilist_traits<NodeTy> >
class iplist : public Traits { // 注1
  Node_Type *Head;  // 注2.链表第一个元素指针。
 
  pointer, reference 等 STL 标准容器类型定义。
 
  this(), ~this()  // 注3。构造,析构。
  begin(), end(), size(), empty(), front(), back() 等标准容器方法。
  push(), pop(), swap(), insert(), erase(), remove() 等操纵方法。
  splice(), erase_if(), unique(), merge(), sort() 等列表常见方法。
}
</syntaxhighlight>

* 注1:使用 Traits 作为基类,其提供 next,prev,sentinel,node 访问策略。
* 注2:链表的 Head 元素在构造时,使用 Traits 提供的策略初始化。
** 一般当新建一个 iplist 的时候,Head == null,没有构造 sentinel 节点。仅当访问 begin(), push() 等方法需要的时候,才会''延迟''创建 sentinel 节点。
** Head.prev 指向 sentinel 节点。 sentinel.prev 指向链表的 Last 节点。
** sentinel.next 为 null。

* 注3:构造中初始化 Head,使用 Traits 中提供的策略方法;析构中使用 Traits 中方法删除节点,及销毁 sentinel 哨兵节点。参见 [[ilist_traits]]
* 注4:size() 方法会遍历所有节点统计数量,所以效率会比较低。也许新策略允许如果保存一个 size 字段更好?
* 注5:sizeof(iplist<T>) 一般是 4,也即 Head 指针的大小。如果 Traits 特化保存有数据,则 sizeof() 可能不是这个值。这种情况出现在 ilist_traits<Value> 特化中。

== iplist 更多说明 ==
模板类 iplist 有如下的三个有趣的状态:
* 1. 链表未构造任何节点状态。此情况下,Head 指针为 null。在此情况下,任何对枚举器的获取(如调用 begin(), end() 等方法)都会透明地转换到状态2.
* 2. 链表为空(empty),但包含一个哨兵(sentinel)节点,以实现 end 枚举器指针。这个哨兵节点通过 Traits::createSentinel() 方法创建,然后链接到 iplist 的末尾。当列表处于这个 empty 空状态的时候,Head 指针指向哨兵节点。哨兵节点一旦创建,则直到列表析构的时候才会被删除。
* 3. 链表可能包含实际的对象,其使用节点双向链接列表连接。一个不变的情况是:列表的第一个节点(Head)的 prev 指针总是指向链表的最后一个节点(哨兵节点),哨兵节点的 next 指针总是 null。

额外:
* 画出图会更清晰一些。
* 用 VC2010 测试的时候,还有一个小编译错误: warning C4355: “this”: 用于基成员初始值设定项列表。在这里: iplist() : Head(this->provideInitialHead()) 。

== ilist ==
模板类 ilist 继承自 iplist<T>,并对其进行了一些小的扩展:
* 提供新的多种构造方式。
* 提供 insert() 的传递引用参数 const T& 重载形式。iplist 使用的是 T* 指针参数。使用这种 insert 需要提供复制构造,如 Value(const Value&).

* ilist 对于 [[Value]], [[GlobalVariable]], [[Instruction]] 等类构成的双向链表特别合适。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!