MySQL InnoDB 中通用双向链表的实现(3)

我们来具体解释一下步骤:
1、UT_LIST_BASE_NODE_T(lock_t) old_locks;定义old_locks为一个链表头对象。
2、UT_LIST_INIT(old_locks, &lock_t::trx_locks);进行初始化,这里UT_LIST_INIT是一个宏

#define UT_LIST_INIT(b, pmf)    \

{    \
(b).count = 0;    \
(b).start = 0;    \
(b).end = 0;    \
(b).node = pmf;    \
UT_LIST_INITIALISE(b);    \
}

非常简单设置全部指针都是NULL,并且初始化node类成员指针指向&lock_t::trx_locks。

3、lock_t* old_lock = lock_rec_copy(lock, heap);我们先不深究这里面,但是他肯定是一种拷贝,完成后他返回一个lock_t*的指针
old_lock

4、接下来就是加入节点,这是一个重头戏,会应用到前面全部的知识。
UT_LIST_ADD_LAST(old_locks, old_lock);
实际上他是一共宏定义
#define UT_LIST_ADD_LAST(LIST, ELEM) ut_list_append(LIST, ELEM)
在经过函数重载调用后实际上他会调用

template <typename List>

void
ut_list_append(
List&    list,
typename List::elem_type*    elem)
{
ut_list_append(
list, elem,
GenericGetNode<typename List::elem_type>(list.node));
}

然后调用:

template <typename List, typename Functor>

void
ut_list_append(
List&    list,
typename List::elem_type*    elem,
Functor    get_node)
{
typename List::node_type&    node = get_node(*elem);


UT_LIST_IS_INITIALISED(list);


node.next = 0;
node.prev = list.end;


if (list.end != 0) {
typename List::node_type&    base_node = get_node(*list.end);


ut_ad(list.end != elem);


base_node.next = elem;
}


list.end = elem;


if (list.start == 0) {
list.start = elem;
}
++list.count;
}

详细描述一下:
首先看一下:

template
void
ut_list_append(
List& list,
typename List::elem_type* elem)
{
ut_list_append(
list, elem,
GenericGetNode(list.node));
}

这里list就是我们初始化的old_locks类型为UT_LIST_BASE_NODE_T(lock_t),elem就是我们copy出来的一个
指向lock_t*的指针old_lock其类型当然也就是UT_LIST_BASE_NODE_T(lock_t)::elem_type*类型实际上就是
lock_t*类型绕了一大圈。
而GenericGetNode(list.node)虽然很长但是我们可以清楚的明白他是调用的构造函数,生成一个匿名对象,typename List::elem_type是用到了ut_list_base定义的类型
elem_type就是一个UT_LIST_BASE_NODE_T(lock_t)::elem_type类型其实就是lock_t类型,而list.node
实际上就是node_ptr类型,初始化已经被定义为&lock_t::trx_locks

接下来由于函数重载的函数调用了

ut_list_append(
List& list,
typename List::elem_type* elem,
Functor get_node)
我们来看看。
typename List::node_type& node = get_node(*elem);
将List(old_locks)中的node成员函数指针进行初始化他指向了old_lock这是结构实际链表结构的位置。
接下来node.next nodex.prev将是可用的了
node.next = 0;
node.prev = list.end;
将节点的后指针设置为NULL,前指针当然设置为list.end的位置
这里也看到他确实放到末尾
if (list.end != 0) {
typename List::node_type& base_node = get_node(*list.end);
ut_ad(list.end != elem);
base_node.next = elem;
}
如果链表不为空,这里再次获得end节点的位置存放到base_node中,
当然也就要将base_node.next设置为我们新加入的节点的指针。
list.end = elem;
将链表头结构的end指针放到我们新插入的elem中。
if (list.start == 0) {
list.start = elem;
}
如果list的start指针为空代表链表为空,那么还需要将start指针指向elem
最后
++list.count;
不解释了。

从整个链表的实现来看仿函数是其中的一个重点,他是一个桥梁其主要分为两步:
1、初始化指向一个类的成员函数,这是指定他的类型,获得他的偏移量
2、初始化指向某一个元素,这是获得他的内存空间地址基地址
有了基地址+偏移量就能够找到实际的元素了。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/47431093490f875e6ff5b99bb0935266.html