HTLSharp - HPC 模板库的 CSharp 版本
HTLSharp 是 HPC 模板库 (HTL) 的 C# 移植和升级版本。
作者:Anthony Daniels
电子邮件: AnthonyDaniels99@gmail.com
引言
HTLSharp 是 HPC 模板库 (HTL) 的 C# 移植和升级版本。HTL
和 HTLSharp
库提供了用于线程安全容器、随机数生成器和分布以及集成序列化引擎的包。有关原始 HTL
的更多信息,请参阅本文。
HTLSharp
库中的包如下
包描述 | 运行状态 |
HtlArchive : 包含对象序列化和反序列化所需的所有类。它包含一个通用的 Archive 树/节点系统以及不同的序列化器包(XML、XDL、JSON 等),用于持久化数据结构。 | Archive 模型 (100%) XML (100%) XDL(100%) JSON (50%) |
HtlBase : 包含使用 HTL 系统使对象可序列化的基类。 | (100%) |
HtlContainer : 包含 HTL 的所有容器类(HtlVector 、HtlMap 、HtlQueue 等)。此集合中的所有容器均可在 HTL 系统中序列化。-(完全可用) | (100%) |
HtlGlobal : 包含全局使用的枚举类型、struct 等。 | (100%) |
HtlGUID : 包含三个全局唯一标识符 (GUID);64位、128位和256位。 | (100%) |
HtlRandNumGen : 包含随机数生成器和随机分布生成器系统。 | (100%) |
HtlString : 包含提供 STL 风格 sprintf() 和 sscanf() 方法的类。 | (100%) |
HtlTest : 包含 HTL 单元测试系统。这是一个基于名称的单元测试系统,类似于 boost,但未使用宏。 | (100%) |
HtlThread : 包含所有线程相关类,包括互斥锁、信号量、线程等。 | (100%) |
需要注意的是,某些包(如信号与槽)并未从原始库移植到 C#。这是因为事件处理基础结构已存在于 C# 基础库中。此外,虽然 C#.NET 中存在一些多线程容器,但它们并未与 HTL 序列化引擎集成,因此决定封装原始的通用容器。值得注意的是,在提供的源代码项目中,有一个单元测试项目说明了代码的用法。
HtlArchive 包
以下各节将演示代码用法。HTL
Archive 包是一个非常强大的序列化系统。该系统使用通用的对象树结构来表示内存中的任何数据结构。该数据结构独立于所使用的序列化方法。因此,相同的序列化结构可以用于 XML 序列化或 JSON 序列化。这使得开发人员可以编写类代码,而无需担心序列化方法。让我们开始吧。
HTLSharp
可以序列化任何集成数据类型(bool
、int
、long
、float
、double
、string
等),以及任何继承自 HtlBase
的类。HtlBase
是一个轻量级对象,只有两个成员变量(m_strType
和 m_objType
)以及两个用于序列化的虚拟函数(Save
和 Load
);m_strType
用于 static object
工厂,用于创建任何继承自 HtlBase
并已注册的对象类型。让我们看看 Save
和 Load
方法。这是它们的原型
public virtual int Save(ref HtlElement ptrCurrNode, ref string strMemVarName, bool blnWithSubObjects)
public virtual int Load(ref HtlElement ptrCurrNode, ref string strMemVarName)
传入的 HtlElement
是正在保存或加载的通用数据结构的当前节点。strMemVarName
是该节点的 string
名称。Save
还包含一个布尔标志,用于指示是否要写入 sub
对象。这在您只想在该级别进行浅层打印而不打印下方所有 sub
对象的情况下很有用。现在让我们来看看它们的实现。TestObj2
是单元测试项目中的一个类。这是该 object
的 save
和 load
方法。
//Virtual Inheritance Serialization Engines
//SERIALIZATION FUNCTIONS///////////////////////////////////////
//!Save member data to the current element node
public override int Save
(ref HtlElement ptrCurrNode, ref string strMemVarName, bool blnWithSubObjects)
{
int intReturn = 0;
//SAFETY CHECK //put at top of all Serialize Methods
if (ptrCurrNode == null) { return 0; };
//CALL PARENT CLASS Serialize()
base.Save(ref ptrCurrNode, ref strMemVarName, blnWithSubObjects);
//strSTDBaseType.clear();
//strBaseType.clear();
//Standard Member Variables
intReturn &= HtlMemVar.SetMemVar<bool>
(ref ptrCurrNode, "m_myBool", ref m_myBool, false);
intReturn &= HtlMemVar.SetMemVar<int>
(ref ptrCurrNode, "m_myInt01", ref m_myInt01, false);
intReturn &= HtlMemVar.SetMemVar<double>
(ref ptrCurrNode, "m_myDouble04", ref m_myDouble04, false);
intReturn &= HtlMemVar.SetMemVar<string>
(ref ptrCurrNode, "m_myString", ref m_myString, false);
//Sub Object Member Variables
if (blnWithSubObjects)
{
intReturn &= HtlMemVar.SetMemVar<TestObj01>
(ref ptrCurrNode, "m_myTestObj", ref m_myTestObj, blnWithSubObjects);
};
return intReturn;
}
//!Load member data from the current element node
public override int Load(ref HtlElement ptrCurrNode, ref string strMemVarName)
{
int intReturn = 0;
//SAFETY CHECK //put at top of all Serialize Methods
if (ptrCurrNode == null) { return 0; };
//CALL PARENT CLASS Serialize()
base.Load(ref ptrCurrNode, ref strMemVarName);
//Standard Member Variables
string strRet = System.String.Empty;
intReturn &= HtlMemVar.GetMemVar<bool>
(ref ptrCurrNode, "m_myBool", ref m_myBool);
intReturn &= HtlMemVar.GetMemVar<int>
(ref ptrCurrNode, "m_myInt01", ref m_myInt01);
intReturn &= HtlMemVar.GetMemVar<double>
(ref ptrCurrNode, "m_myDouble04", ref m_myDouble04);
intReturn &= HtlMemVar.GetMemVar<string>
(ref ptrCurrNode, "m_myString", ref m_myString);
intReturn &= HtlMemVar.GetMemVar<TestObj01>
(ref ptrCurrNode, "m_myTestObj", ref m_myTestObj);
return intReturn;
}
Save
方法首先调用基类 Save
方法。然后,它继续设置类的所有成员变量。在这种情况下,有一个 bool
、一个 int
、一个 double
、一个 string
,以及一个类型为 TestObj01
的子对象,它也继承自 HtlBase
。请注意,TestObj01
包含在 print sub object
s 的布尔检查中。通过调用 HtlMemVar.SetMemVar<T>()
方法来实现成员变量的设置。您传入当前节点的引用、该成员变量的 string
名称以及对象的引用。请注意,所有基对象成员变量的 blnWithSubObjects
都设置为 false
。
类似地,Load
方法调用基类 Load
,然后继续调用相应的 GetMemVar<T>
函数。值得注意的是,同时拥有 Save
和 Load
方法的原因是,有时开发人员希望拥有只写成员变量(例如 GUID
)。该系统也适用于 HTL 中的所有容器。这是 HtlVector
被序列化的示例。
intReturn &= HtlMemVar.SetMemVar<HtlVector<TestObj01>>
(ref ptrCurrNode, "m_arrObjs", ref m_arrObjs, true);
调用 save
后,用户就可以使用所需的序列化器进行序列化。以下示例使用的是 XDL 序列化器。
TestObj02 obj = new TestObj02();
string strOut = System.String.Empty;
string strTopName = "rootobject";
HtlXDLWriter writer = new HtlXDLWriter();
HtlElement root = new HtlElement();
//serialize
obj.Save(ref root, ref strTopName, true);
root.UpdateIndexes();
writer.SaveXDLTree(ref root, ref strOut, true);
// Write the string to a file.
System.IO.StreamWriter outfile =
new System.IO.StreamWriter("HtlTestArch_XDL_Obj02Nested.out");
outfile.Write(strOut);
outfile.Close();
//clear the values
obj.m_myBool = false;
obj.m_myInt01 = -1;
obj.m_myDouble04 = -1.0f;
obj.m_myString = "null";
obj.m_myTestObj.Reset();
//now read it back in and deserialize
HtlElementIndex xelem = new HtlElementIndex();
HtlXDLReader reader = new HtlXDLReader();
HtlElement readroot = new HtlElement();
reader.LoadXDLTree(ref readroot, ref strOut, ref xelem);
obj.Load(ref readroot, ref strTopName);
HtlContainer 包
我们决定为 C#.NET 库中的 Vector
(List
)、Map
(Dictionary
) 和 Queue
类提供包装器。使用这三个基本容器,您可以满足大部分需求。但是,如果需要其他线程安全包装,它们为用户提供了创建的良好路线图。如前所述,容器的主要目的是(除了多线程支持)与归档系统集成。随附的单元测试(在 HtlTestSuite
中)提供了 XML 和 XDL 输出示例。JSON 正在开发中,很快就会添加。请参阅单元测试以进行多线程测试和验证。
HtlRandNumGen 包
有两个随机数生成器(LCG 和 Mersenne Twister)和五个分布(HtlUniform
、HtlGamma
、HtlGaussian
、HtlPoisson
、HtlExponential
)。提供了 Uniform、Exponential 和 Gaussian 的单元测试。RNGs 非常易于使用。只需创建对象,调用 initialize()
获取种子,然后调用 next()
获取下一个 RNG。HtlUniform
还可以使用 intGetNextAB()
或 sngGetNextAB()
函数在指定范围内生成 RNG。
HtlGUID 包
提供了 64 位、128 位和 256 位全局唯一标识符。它们继承自 HtlBase
,因此可以直接序列化。需要注意的是,它们是对称的,与 windows GUID
类不同。所有段的宽度都相等。这是 HtlGUID128
的一个示例
975D3F24-F81FF9EB-2F556151-5F9D2204
这使得它们更容易使用,并且显示效果也更整洁。
HtlTest 包
HtlNode
包具有类似于归档包中 HtlElement
类的基于节点的架构。HtlTestNode
可以包含其他测试节点,根节点会触发所有子节点。有关其用法的良好示例,请参阅 HtlTestSuite
。每个 HtlTestNode
都有以下虚拟函数,这些函数在子类中按需实现。这些方法在 public PerformTest()
方法中按顺序触发。
public virtual int SetupTest() { return 0; }
public virtual int PreProcessTest() { return 0; }
public virtual int RunTest() { return 0; }
public virtual int PostProcessTest() { return 0; }
public virtual int ClearTest() { return 0; }