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,一经查实,立即删除!

相关文章

重学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;使得数据库在设计上通常难以兼顾到性…

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;其实就是实名…

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

前言 今年报考了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;结合场景使…

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

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

Jenkins插件使用问题总结

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

【命令操作】Linux三剑客之awk详解 _ 统信 _ 麒麟 _ 方德

原文链接&#xff1a;【命令操作】Linux三剑客之awk详解 | 统信 | 麒麟 | 方德 Hello&#xff0c;大家好啊&#xff01;今天带来一篇关于Linux三剑客之awk命令详解的文章。在文本处理工具中&#xff0c;awk以其强大的文本筛选、格式化和数据处理功能而闻名。它能够在处理结构化…

操作系统概念(一)——IOMMU学习

系列文章目录 提示&#xff1a;本系列主要记录工作过程中遇到的操作系统基础概念以及工作原理 第一章 操作系统之IOMMU 文章目录 系列文章目录1. 设备访问内存的几种主要方式1.1 传统的 I/O 访问&#xff08;程序控制 I/O&#xff09;1.2 直接内存访问&#xff08;DMA&#xf…

计算机网络:网络层 —— IP 多播技术

文章目录 基本概念IP多播地址和多播组 IP多播的类型硬件多播将IPv4多播地址映射为多播MAC地址 基本概念 多播&#xff08;Multicast&#xff0c;也称为组播&#xff09;是一种实现“一对多”通信的技术&#xff0c;允许一台或多台主机&#xff08;多播源&#xff09;发送单一数…

windows运行ffmpeg的脚本报错:av_ts2str、av_ts2timestr、av_err2str => E0029 C4576

问题描述 我目前的环境是&#xff1a; 编辑器&#xff1a; Microsoft Visual Studio Community 2022 (64 位) 运行的脚本是ffmpeg自带的remux样例&#xff0c;只不过我想用c语言执行这个样例。在执行的过程中报错如下图&#xff1a; C4576 后跟初始值设定项列表的带圆括…

翻译工具开发技术笔记:《老挝语翻译通》app支持语音识别翻译功能,怎么提高语音识别的准确度呢?

《老挝语翻译通》app是一款专为老挝语翻译设计的免费工具&#xff0c;支持文本翻译、老挝文OCR文字识别提取、文字转语音。这款工具以其技术优势和用户友好的界面&#xff0c;为用户提供了便捷的老挝语翻译体验。 技术特点 文本翻译&#xff1a;支持双语输入&#xff0c;提供精…

Linux系统每日定时备份mysql数据

一、创建存储脚本的文件夹 创建文件夹&#xff0c;我的脚本放在/root/dbback/mysql mkdir ... cd /root/dbback/mysql 二、编写脚本 vi backup_mysql.sh 复制脚本内容 DB_USER"填写用户名" DB_PASSWORD"填写密码" DB_NAME"数据库名称" # …

MySQL基础-单表查询

语法 select [distinct] 列名1&#xff0c;列名2 as 别名... from数据表名 where组前筛选 group by分组字段 having组后筛选 order by排序的列 [asc | desc] limit 起始索引&#xff0c;数据条数 测试数据 # 建测试表 create table products (id int primary key a…