strongswan链表结构

链表结构定义如下,public成员为公共的方法,count,first和last为私有成员,count表示链表中元素的数量,first和last分别指向链表的头和尾。public(linked_list_t结构)定义了一系列操作链表的方法,其必须为第一个结构成员,方便在公共方法和私有结构间转换。

struct private_linked_list_t {linked_list_t public;int count;element_t *first;element_t *last;
};

链表元素结构element_t如下,包括值value,和指向前一个(previous)和后一个元素(next)的两个指针:

struct element_t {void *value;element_t *previous;element_t *next;
};

如下函数创建通用的链表元素结构。

static element_t *element_create(void *value)
{element_t *this;INIT(this,.value = value,);return this;
}

创建新链表

创建新的链表,实例化链表结构,这里主要初始化了链表的公共方法,没有初始化私有成员。

linked_list_t *linked_list_create()
{private_linked_list_t *this;INIT(this,.public = {.get_count = _get_count,.create_enumerator = _create_enumerator,.reset_enumerator = (void*)_reset_enumerator,.get_first = _get_first,.get_last = _get_last,.find_first = _find_first,.insert_first = _insert_first,.insert_last = _insert_last,.insert_before = (void*)_insert_before,...},);return &this->public;

链表元素操作

向链表尾部插入元素时,对于链表为空的情况,链表成员first和last都指向此元素。对于链表非空的情况,链表中原有最后一个元素last的next指向新元素,新元素的previous指向原有最后一个元素。新元素保存为最后一个元素last。

METHOD(linked_list_t, insert_last, void, private_linked_list_t *this, void *item)
{element_t *element = element_create(item);if (this->count == 0) {    /* first entry in list */this->first = element;this->last = element;} else {element->previous = this->last;this->last->next = element;this->last = element;}this->count++;

链表起初只有一个元素(1st_elem),在尾部增加第二个元素之后如下图所示:

this->first                     this->first  |---<-------------<-------------------||                                |   |                                     |   
this->last                               |   |               this->last            |   |                                |   |                      |              |   |-----------|                     |-----------|            |-----------|        |   |           |--pre=NULL           |           |--pre=NULL  |           |--pre---|   |  1st_elem |                     |  1st_elem |            |  2nd_elem |            |           |--next=NULL          |           |--next----->|           |--next=NULL |-----------|                     |-----------|            |-----------|            

方法insert_first在链表首部插入一个元素,递增链表元素计数。

METHOD(linked_list_t, insert_first, void, private_linked_list_t *this, void *item)
{element_t *element = element_create(item);if (this->count == 0) {/* first entry in list */this->first = element;this->last = element;} else {element->next = this->first;this->first->previous = element;this->first = element;}this->count++;

链表起初只有一个元素(1st_elem),在首部增加第二个元素之后如下图所示:

this->first                     this->first   |---------<------<-----------------------------|                             |                               |     |                                              |
this->last                              |     |                     this->last               |   |                               |     |                             |                |   |-----------|                   |--------------|                 |---------------|        |     |           |--pre=NULL         |              |--pre=NULL       |               |--pre---|   |  1st_elem |                   | new_1st_elem |                 |  old_1st_elem |             |           |--next=NULL        |              |--next---------->|               |--next=NULL  |-----------|                   |--------------|                 |---------------|             

释放元素时,先行保存元素在链表中的下一个next和前一个元素previous。如果下一个元素有值,拿起previous应当指向上上个元素;否则,删除的为链表最后一个元素,previous变成最后一个元素。

如果前一个元素有值,其last应当指向下下个元素;否则,删除的为链表第一个元素,next变成第一个元素。

链表中的元素个数递减一,如果递减之后等于0,将链表的first和last指针置空。函数返回链表中被删除元素的下一个元素。

static element_t* remove_element(private_linked_list_t *this, element_t *element)
{element_t *next, *previous;next = element->next;previous = element->previous;free(element);if (next)next->previous = previous;elsethis->last = previous;if (previous)previous->next = next;elsethis->first = next;if (--this->count == 0){this->first = NULL;this->last = NULL;}return next;

链表枚举器

链表的枚举器结构定义如下,public成员为公共的方法,list和current为私有成员。public必须为第一个结构成员,方便在公共方法和私有结构间切换。

struct private_enumerator_t {enumerator_t public;private_linked_list_t *list;element_t *current;
};

枚举器结构的公共方法有以下三个。

struct enumerator_t {bool (*enumerate)(enumerator_t *this, ...);bool (*venumerate)(enumerator_t *this, va_list args);void (*destroy)(enumerator_t *this);
};

create_enumerator函数创建枚举器,初始化private_enumerator_t结构,链表结构实现了venumerate函数,enumerate函数使用枚举器默认的。私有成员list初始化为链表结构this,current成员指向链表首个元素。

METHOD(linked_list_t, create_enumerator, enumerator_t*, private_linked_list_t *this)
{   private_enumerator_t *enumerator;INIT(enumerator,.public = {.enumerate = enumerator_enumerate_default,.venumerate = _enumerate_current,.destroy = (void*)free,},.list = this,.current = this->first,);return &enumerator->public;

枚举器要求必须实现venumerate方法,其默认函数(enumerator_enumerate_default)是对venumerate的封装。此函数接受可变数量的参数,之后将这些参数传入venumerate方法。

bool enumerator_enumerate_default(enumerator_t *enumerator, ...)
{va_list args;bool result;if (!enumerator->venumerate) {DBG1(DBG_LIB, "!!! ENUMERATE DEFAULT: venumerate() missing !!!");return FALSE;}va_start(args, enumerator);result = enumerator->venumerate(enumerator, args);va_end(args);return result;

枚举器初始化的venumerate函数如下,在首次调用之后,其公共方法venumerate更换为_enumerate_next,用于获取枚举器的下一个元素。

METHOD(enumerator_t, enumerate_current, bool,private_enumerator_t *this, va_list args)
{this->public.venumerate = _enumerate_next;return do_enumerate(this, args);
}

初始化时,枚举器的current指向了链表结构的首个元素,如果current和传入参数都有效,将current元素的值赋予参数中。对于链表结构,可变参数的数量为1。

如果current为空,返回FALSE,表示整个枚举过程结束,链表结构的元素遍历完成。

static bool do_enumerate(private_enumerator_t *this, va_list args)
{   void **item;VA_ARGS_VGET(args, item);if (!this->current) return FALSE;if (item)*item = this->current->value;return TRUE;

通常在遍历第二个元素时,枚举器的venumerate函数换成了enumerate_next,枚举器的私有成员current指向链表下一个元素。do_enumerate执行以上的取值操作,取出下一个链表元素。

METHOD(enumerator_t, enumerate_next, bool, private_enumerator_t *this, va_list args)
{if (this->current)this->current = this->current->next;return do_enumerate(this, args);
}

枚举器使用完之后,需要由reset_enumerator复位,枚举器的current再次指向链表结构的首个元素,枚举器的公共方法venumerate恢复为指向enumerate_current函数。

METHOD(linked_list_t, reset_enumerator, void,private_linked_list_t *this, private_enumerator_t *enumerator)
{enumerator->current = this->first;enumerator->public.venumerate = _enumerate_current;
}

strongswan-5.9.14

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/885022.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端react常见面试题目(basic)

1. 如果 React 组件的属性没有传值&#xff0c;它的默认值是什么? 如果一个 React 组件的属性&#xff08;props&#xff09;没有传值&#xff0c;那么它的默认值会是 undefined。你可以通过组件内部的逻辑来设置默认值&#xff0c;比如使用逻辑运算符或者 ES6 的默认参数。 …

重学SpringBoot3-整合 Elasticsearch 8.x (一)客户端方式

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ 重学SpringBoot3-整合 Elasticsearch 8.x &#xff08;一&#xff09;客户端方式 1. 为什么选择 Elasticsearch&#xff1f;2. Spring Boot 3 和 Elasticsearch 8.x 的集…

【网络安全渗透测试零基础入门】Vulnhub靶机Kioptrix level-4 多种姿势渗透详解,收藏这一篇就够了!

前言 这是阳哥给粉丝盆友们整理的网络安全渗透测试入门阶段Vulnhub靶场实战阶段教程 喜欢的朋友们&#xff0c;记得给我点赞支持和收藏一下&#xff0c;关注我&#xff0c;学习黑客技术。 环境配置 服务版本探测&#xff1a;sudo nmap -sT -sV -sC -O -p22,80,139,445 22端…

由中文乱码引来的一系列学习——Qt

前言 解决中文引起的乱码&#xff0c;并不难&#xff0c;网上一搜就有好几个方法任君选择&#xff0c;但是解决乱码的这些方法的原理是什么&#xff0c;我一直没太明白。 这次项目需要在Android环境下运行&#xff0c;而根据Qt跨平台的特性&#xff0c;我一般是在Windows环境…

浅析数据库缓存一致性问题

在真实的业务场景中&#xff0c;我们的业务的数据——例如订单、会员、支付等——都是持久化到数据库中的&#xff0c;因为数据库能有很好的事务保证、持久化保证。但是&#xff0c;正因为数据库要能够满足这么多优秀的功能特性&#xff0c;使得数据库在设计上通常难以兼顾到性…

解决SRS推送webrtc流卡顿问题

目录 1.问题描述2.原因分析3.ffmpeg去掉B帧的方法3.1 命令行推流3.2 ffmpeg源码推流 1.问题描述 使用ffmpeg通过rtmp协议推流给SRS&#xff0c;然后浏览器通过webrtc拉取播放流&#xff0c;经多次测试发现webrtc播放流总是卡顿&#xff0c;而拉取rtmp流是正常的。 2.原因分析…

docker加载目录中所有的镜像

docker加载目录中所有的镜像 首先我们知道读取单个命令如下: docker load -i example_image.tar.gz读取两三个也是: docker load -i image1.tar.gz image2.tar.gz image3.tar.gz但是如果是几十个&#xff0c;那么上面的命令就显得捉襟见肘了&#xff1b;比如当前我有个image…

element plus el-form自定义验证输入框为纯数字函数

element plus 的el-form 使用自定义验证器&#xff0c;验证纯数字&#xff0c;禁止输入小数、中文、字母、特殊符号。input的maxlength为最大输入多少位长度 效果图 <el-form ref"dataFormRef" :model"dataForm" :rules"dataRules" label-w…

jira如何查看历史Sprint

方法一&#xff1a;通过看板模块查看历史 Sprint 进入看板模块 在项目的看板中&#xff0c;找到并点击“模块项”。在右侧历史记录中选择一个模块项。 查看 Sprint 历史 进入模块项界面后&#xff0c;点击“搜索”按钮旁边的“更多”下拉菜单。勾选“Sprint”选项&#xff0c;…

阿里云 DataWorks 正式支持 SelectDB Apache Doris 数据源,实现 MySQL 整库实时同步

SelectDB 是由飞轮科技基于 Apache Doris 内核打造的现代化数据仓库&#xff0c;支持大规模实时数据上的极速查询分析。 通过实时、统一、弹性、开放的核心能力&#xff0c;能够为企业提供高性价比、简单易用、安全稳定、低成本的实时大数据分析支持。SelectDB 具备世界领先的实…

OV(企业型)通配符域名SSL证书

SSL证书是由CA机构签发的&#xff0c;相信这一点大家都知道&#xff0c;然而目前全世界兼容性可以达到99%机构仅有&#xff1a;GlobalSign、DigiCert、Sectigo、Certum&#xff0c;最后一家还是勉强。 SSL证书选择OV&#xff08;国内有人称之为企业型&#xff09;其实就是实名…

使用docker-compose实现不停机部署/灰度发布

使用 Docker Compose 实现不停机部署&#xff08;零 downtime 部署&#xff09;或灰度发布是常见的需求&#xff0c;可以通过以下几种方法来实现&#xff1a; 方法一&#xff1a;使用 docker-compose up --scale 和 docker-compose stop 步骤 备份现有服务&#xff1a; 在进行…

软考系统分析师知识点三五: 考前强记知识点

前言 今年报考了11月份的软考高级&#xff1a;系统分析师。 考试时间&#xff1a;11月9日。 倒计时&#xff1a;2天。 目标&#xff1a;优先应试&#xff0c;其次学习&#xff0c;再次实践。 复习计划第四阶段&#xff1a;考前强记知识点。 考前强记知识点 系统分析主要任…

基础算法——排序算法(冒泡排序,选择排序,堆排序,插入排序,希尔排序,归并排序,快速排序,计数排序,桶排序,基数排序,Java排序)

1.概述 比较排序算法 算法最好最坏平均空间稳定思想注意事项冒泡O(n)O( n 2 n^2 n2)O( n 2 n^2 n2)O(1)Y比较最好情况需要额外判断选择O( n 2 n^2 n2)O( n 2 n^2 n2)O( n 2 n^2 n2)O(1)N比较交换次数一般少于冒泡堆O( n l o g n nlogn nlogn)O( n l o g n nlogn nlogn)O( n l…

探索 Python 视频编辑新纪元:MoviePy库的神秘面纱

文章目录 探索 Python 视频编辑新纪元&#xff1a;MoviePy 库的神秘面纱第一部分&#xff1a;背景介绍第二部分&#xff1a;MoviePy 是什么&#xff1f;第三部分&#xff1a;如何安装这个库&#xff1f;第四部分&#xff1a;简单的库函数使用方法第五部分&#xff1a;结合场景使…

优雅的遍历JSONArray,获取里面的数据

最近看到有个同事在遍历json数组的时候&#xff0c;用for循环写了一层有一层&#xff0c;那么是否有简便的写法呢&#xff1f;当然有了&#xff0c;下面就有用流的行驶&#xff0c;优雅的遍历数组&#xff0c;获取我们想要的数据 public static void main(String[] args) {Str…

计算机网络:网络层 —— 多播路由选择协议

文章目录 多播路由选择协议多播转发树构建多播转发树基于源树的多播路由选择建立广播转发树建立多播转发树 组共享树的多播路由选择基于核心的生成树的建立过程 因特网的多播路由选择协议 多播路由选择协议 仅使用 IGMP 并不能在因特网上进行IP多播。连接在局域网上的多播路由…

Jenkins插件使用问题总结

Git Push插件 插件介绍 主要是用于git推送代码到远程仓库中使用&#xff0c;插件地址 pipeline中使用 官方说明中只有一句代码gitPush(gitScm: scm, targetBranch: env.BRANCH_NAME, targetRepo: origin) 流水线语法中也做的不齐全所以一开始我老是设置错&#xff0c;导致代…

MYSQL备库的并行复制

备库在消费中转日志时&#xff0c;其实可以分多个线程同时对多个事务进行消费&#xff0c;但是要满足2个基本原则&#xff1a; 1.涉及同一行数据的多个事务必须在同一个线程中执行&#xff0c;否则会导致数据不一致 2.同一个事务不能被拆开 MYSQL 5.6的并行复制策略&#xff…

委托, Lambda表达式 , 事件

1&#xff1a;什么是委托 委托就是持有一个或者多个方法的对象&#xff01;并且该对象可以执行&#xff0c;可以传递。 1.1&#xff1a; 声明委托类型 委托可以持有方法&#xff0c;可以声明它是一种应用类型 声明关键字&#xff1a;delegete void ActCute(); 定义委托类型的对…