通过解析库探究函数式抽象代价 ( ini 解析示例补充)
上一篇 用 HexColor 作为示例,可能过于简单
这里再补充一个 ini 解析的示例
由于实在写不动用其他库解析 ini 了, 春节都要过完了,累了,写不动了,
所以随意找了一份解析ini的库, 仅供参考,对比不准确,毕竟完整库包含了更多功能
先看看结果
BenchmarkDotNet v0.13.12, Windows 11 (10.0.22631.3085/23H2/2023Update/SunValley3)
Intel Core i7-9750H CPU 2.60GHz, 1 CPU, 12 logical and 6 physical cores
.NET SDK 8.0.200
[Host] : .NET 8.0.2 (8.0.224.6711), X64 RyuJIT AVX2
DefaultJob : .NET 8.0.2 (8.0.224.6711), X64 RyuJIT AVX2
Method | Mean | Error | StdDev | Gen0 | Gen1 | Allocated |
---|---|---|---|---|---|---|
Hande_Ini | 567.9 ns | 11.24 ns | 21.66 ns | 0.2851 | - | 1.75 KB |
RuQu_Ini | 1,691.4 ns | 33.48 ns | 64.51 ns | 0.4177 | - | 2.56 KB |
IniDataParser | 4,836.3 ns | 94.44 ns | 167.87 ns | 1.1215 | 0.0076 | 6.91 KB |
// * Legends *
Mean : Arithmetic mean of all measurements
Error : Half of 99.9% confidence interval
StdDev : Standard deviation of all measurements
Gen0 : GC Generation 0 collects per 1000 operations
Gen1 : GC Generation 1 collects per 1000 operations
Allocated : Allocated memory per single operation (managed only, inclusive, 1KB = 1024B)
1 ns : 1 Nanosecond (0.000000001 sec)
总结
delegate
肯定会有调用消耗,ini 场景使用的函数远多于 HexColor ,可以看到消耗大了很多
先看来自 dotnet Microsoft.Extensions.Configuration
中解析 ini 的代码
public static IDictionary<string, string?> Read(string content)
{
var data = new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase);
using (var reader = new StringReader(content))
{
string sectionPrefix = string.Empty;
while (reader.Peek() != -1)
{
string rawLine = reader.ReadLine()!; // Since Peak didn't return -1, stream hasn't ended.
string line = rawLine.Trim();
// Ignore blank lines
if (string.IsNullOrWhiteSpace(line))
{
continue;
}
// Ignore comments
if (line[0] is ';' or '#' or '/')
{
continue;
}
// [Section:header]
if (line[0] == '[' && line[line.Length - 1] == ']')
{
// remove the brackets
sectionPrefix = string.Concat(line.AsSpan(1, line.Length - 2).Trim(), ConfigurationPath.KeyDelimiter);
continue;
}
// key = value OR "value"
int separator = line.IndexOf('=');
if (separator < 0)
{
throw new FormatException(rawLine);
}
string key = sectionPrefix + line.Substring(0, separator).Trim();
string value = line.Substring(separator + 1).Trim();
// Remove quotes
if (value.Length > 1 && value[0] == '"' && value[value.Length - 1] == '"')
{
value = value.Substring(1, value.Length - 2);
}
if (data.ContainsKey(key))
{
throw new FormatException(key);
}
data[key] = value;
}
}
return data;
}
再来看看部分函数语义优化的代码
public class Ini
{
private static Ini instance = new Ini();
public Func<IPeeker<char>, bool> WhiteSpace = Chars.IngoreWhiteSpace.Map(i => i > 0);
public Func<IPeeker<char>, bool> Comment = Chars.In(";#/").Delimited(Chars.NotCRLF.ToSlice().Opt(), Chars.IsCRLF, "Comment not right").Map((c, x, y, z) => c);
public Func<IPeeker<char>, string> SectionName = Chars.Is('[').Delimited(Chars.Not(']').ToSlice().Once("Section name is required."), Chars.Is(']'), "Section name must end with ']'").Map((c, x, y, z) => y?.ToString());
public Func<IPeeker<char>, string> Key = Chars.Not('=').ToSlice().Once("key is required.").Map(i => i.ToString());
public Func<IPeeker<char>, char> Separater = Chars.Is('=').Once("Section name is required.");
public Func<IPeeker<char>, string> Value = Chars.NotCRLF.ToSlice().Once("value is required.").Map(i =>
{
var v = i.ToString().Trim();
return v.StartsWith('"') ? v[1..^1] : v;
});
public IDictionary<string, string> ParseString(string content)
{
var input = Input.From(content);
var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
while (input.TryPeek(out var v))
{
if (!(WhiteSpace(input) || Comment(input) || Section(input, dict)))
{
throw new NotSupportedException(v.ToString());
}
}
return dict;
}
public bool SectionContentEnd(IPeeker<char> input)
{
return !input.TryPeek(out var v) || v is '[';
}
public bool Section(StringPeeker input, Dictionary<string, string> dict)
{
var name = SectionName(input);
if (name == null) return false;
while (!SectionContentEnd(input))
{
if (WhiteSpace(input) || Comment(input))
{
continue;
}
SectionKV(input, dict, name);
}
return true;
}
public void SectionKV(StringPeeker input, Dictionary<string, string> dict, string name)
{
var k = Key(input);
Separater(input);
var v = Value(input);
k = $"{name}:{k.Trim()}";
dict.Add(k, v.Trim());
}
public static IDictionary<string, string> Parse(string content)
{
return instance.ParseString(content);
}
}
最后截取 部分 ini 解析库的代码 仅供参考
public IniData Parse(string iniDataString)
{
IniData iniData = (Configuration.CaseInsensitive ? new IniDataCaseInsensitive() : new IniData());
iniData.Configuration = Configuration.Clone();
if (string.IsNullOrEmpty(iniDataString))
{
return iniData;
}
_errorExceptions.Clear();
_currentCommentListTemp.Clear();
_currentSectionNameTemp = null;
try
{
string[] array = iniDataString.Split(new string[2] { "\n", "\r\n" }, StringSplitOptions.None);
for (int i = 0; i < array.Length; i++)
{
string text = array[i];
if (text.Trim() == string.Empty)
{
continue;
}
try
{
ProcessLine(text, iniData);
}
catch (Exception ex)
{
ParsingException ex2 = new ParsingException(ex.Message, i + 1, text, ex);
if (Configuration.ThrowExceptionsOnError)
{
throw ex2;
}
_errorExceptions.Add(ex2);
}
}
if (_currentCommentListTemp.Count > 0)
{
if (iniData.Sections.Count > 0)
{
iniData.Sections.GetSectionData(_currentSectionNameTemp).TrailingComments.AddRange(_currentCommentListTemp);
}
else if (iniData.Global.Count > 0)
{
iniData.Global.GetLast().Comments.AddRange(_currentCommentListTemp);
}
_currentCommentListTemp.Clear();
}
}
catch (Exception item)
{
_errorExceptions.Add(item);
if (Configuration.ThrowExceptionsOnError)
{
throw;
}
}
if (HasError)
{
return null;
}
return (IniData)iniData.Clone();
}
完整代码参考 https://github.com/fs7744/ruqu
通过解析库探究函数式抽象代价 ( ini 解析示例补充)的更多相关文章
- 爬虫(五)—— 解析库(二)beautiful soup解析库
目录 解析库--beautiful soup 一.BeautifulSoup简介 二.安装模块 三.Beautiful Soup的基本使用 四.Beautiful Soup查找元素 1.查找文本.属性 ...
- 【开源】libinimini:适用于单片机的极简 ini 解析库
介绍说明 最近自己基于 XR872 在做一个小作品练习练习,具备可以配置的功能,选择了使用 ini 作为配置文件.我调研了网上常见的 ini 解析库,几乎都涉及到了 fopen()/fgets().. ...
- OpenStack配置解析库oslo.config的使用方法
OpenStack的oslo项目旨在独立出系统中可重用的基础功能,oslo.config就是其中一个被广泛使用的库,该项工作的主要目的就是解析OpenStack中命令行(CLI)或配置文件(.conf ...
- C++的Json解析库:jsoncpp和boost(转)
原文转自 http://blog.csdn.net/hzyong_c/article/details/7163589 JSON(JavaScript Object Notation)跟xml一样也是一 ...
- [转]C++的Json解析库:jsoncpp和boost
JSON(JavaScript Object Notation)跟xml一样也是一种数据交换格式,了解json请参考其官网http://json.org,本文不再对json做介绍,将重点介绍c++的j ...
- golang常用库:配置文件解析库-viper使用
一.viper简介 viper 配置解析库,是由大神 Steve Francia 开发,他在google领导着 golang 的产品开发,他也是 gohugo.io 的创始人之一,命令行解析库 cob ...
- Boost.JSON Boost的JSON解析库(1.75首发)
目录 目录 Boost的1.75版本新库 JSON库简介 JSON的简单使用 编码 最通用的方法 使用std::initializer_list json对象的输出 两种对比 解码 简单的解码 增加错 ...
- 解析库beautifulsoup
目录 一.介绍 二.遍历文档树 三.搜索文档树(过滤) 四.修改文档树 五.总结 一.介绍 Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的 ...
- Pugixml一种快速解析XML文件的开源解析库
Pugixml是一个轻量级的C++ XML开源解析库,DOM形式的解析器.接口和丰富的遍历和修改操作,快速的解析,此外支持XPath1.0实现数据查询,支持unicode编码: 使用Pugixml可通 ...
- Tomjson - 一个"短小精悍"的 json 解析库
Tomjson,一个"短小精悍"的 json 解析库,tomjson使用Java语言编写,主要作用是把Java对象(JavaBean)序列化为json格式字符串,将json格式字符 ...
随机推荐
- zznu 1632
表达式求值 递归求解~~ #include<cstdio> #include<cstring> #include<cstdlib> #include<cmat ...
- socket TCP DPT 网络编程
复习: ARP协议: 广播和单播 通过ip地址获得mac地址 机器A发起一个arp请求(只包含A的ip地址) 交换机接收到请求,广播这条消息 所有的机器都会接受到这条请求,只有需要寻找的机器B的ip地 ...
- [译] kubernetes:kube-scheduler 调度器代码结构概述
本文翻译自 https://github.com/kubernetes/community/blob/master/contributors/devel/sig-scheduling/scheduli ...
- spring boot 中WebMvcConfigurer相关使用总结
本文为博主原创,未经允许不得转载: WebMvcConfigurer 为spring boot中的一个接口,用来配置web相关的属性或工具插件,比如消息转换器,拦截器,视图处理器,跨域设置等等. 在S ...
- [kubernetes]安装dashboard
前言 kubernetes官方文档中的web UI网页管理工具是kubernetes-dashboard,可提供部署应用.资源对象管理.容器日志查询.系统监控等常用的集群管理功能.为了在页面上显示系统 ...
- Mongo-文档主键-ObjectId
文档主键 文档主键时 _id,如果插入文档时,没有传入则自动生产ObjectId 作为文档主键 文档主键要求在集合中唯一 文档主键可以时另一个文档,被当作字符串对象处理 ObjectId对象 获取文档 ...
- [转帖]028.PGSQL-用户创建、表空间创建、数据库创建、schema创建、表创建、生成测试数据、指定搜索路径、
https://www.cnblogs.com/star521/p/15054341.html 登录数据库 su postgres #注意这里postgers 前后都有空格 psql -U post ...
- [转帖]使用 goofys 挂载 S3 bucket 为文件系统
https://xie.infoq.cn/article/7f178e0a1315f758d77c6c2bb 背景 公司的 gitlab 目前都是直接存储在物理盘上,为了确保数据不会丢失,需要重复多次 ...
- [转帖]linux shell 中数组的定义和for循环遍历的方法
https://www.cnblogs.com/ysk123/p/11510718.html linux 中定义一个数据的语法为: variable=(arg1 arg2 arg3 ....) 中间用 ...
- [转帖]THE OSWATCHER ANALYZER USER'S GUIDE
oswbba THE OSWATCHER ANALYZER USER'S GUIDE Carl DavisMay 7, 2019 To see how to use this tool and it' ...