Author: Anthony Daniels
Email: AnthonyDaniels99@gmail.com
Download source
Introduction
HTLSharp is a C# port and upgrade of the HPC Template Library (HTL). The HTL
and the HTLSharp
library provide packages for thread safe containers, random number generators and distributions, as well as an integrated serialization engine. For more information on the original HTL
, see this article.
The packages in the HTLSharp
library are as follows:
Package Description | Operational Status |
HtlArchive : Contains all of the classes necessary for serialization and deserialization of objects. It contains a generic archive tree / node system and different serializer packages (XML, XDL, JSON, etc.) that persist the data structure. | Archive Model (100%) XML (100%) XDL(100%) JSON (50%) |
HtlBase : Contains the base classes for making objects serializable using the HTL system. | (100%) |
HtlContainer : Contains all of the container classes of the HTL (HtlVector , HtlMap , HtlQueue , etc.). All containers in this set are serializable in the HTL system. – (fully operational) | (100%) |
HtlGlobal : Contains globally used enumerated types, struct s, etc. | (100%) |
HtlGUID : Contains the three Global Unique Identifiers (GUID); 64bit, 128bit, and 256bit | (100%) |
HtlRandNumGen : Contains a system for random number generators and random distribution generators. | (100%) |
HtlString : Contains the class that provides STL style sprintf() and sscanf() methods. | (100%) |
HtlTest : Contains the HTL unit testing system. This is a test name based unit test system similar to boost, but no macros were used in it. | (100%) |
HtlThread : Contains all thread related classes including mutexes, semaphores, threads, etc. | (100%) |
It should be noted that some packages such as the Signals and Slots were not ported to C# from the original library. This is because the event handling infrastructure already exists in the base C# library. Also, while some multithreaded containers exist in C#.NET, they were not integrated with the HTL serialization engine so the decision was made to wrap the original generic containers. It should be noted that in the source code project provided, there is a unit testing project that illustrates the usage of the code.
HtlArchive Package
The following sections will illustrate the code usage. The HTL
Archive package is a very powerful serialization system. The system uses a generic object tree structure to represent any data structure in memory. That data structure is independent of the serialization method used. So the same serialization structure can feed either an XML serialization or a JSON serialization. This allows for the developer to write code for classes without worrying about the method of serialization. Let's get started.
HTLSharp
can serialize any integrated data type (bool
, int
, long
, float
, double
, string
, etc.) as well as any class that inherits from HtlBase
. HtlBase
is a lightweight object that has only two member variables (m_strType
, and m_objType
) as well as two virtual functions used for the serialization (Save
and Load
); The m_strType
is used in the static object
factory for creating any type of object that inherits from HtlBase
and has been registered. Let us look at the Save
and Load
methods. Here are their prototypes:
public virtual int Save(ref HtlElement ptrCurrNode, ref string strMemVarName, bool blnWithSubObjects)
public virtual int Load(ref HtlElement ptrCurrNode, ref string strMemVarName)
The HtlElement
passed in is the current node of the generic data structure being saved or loaded. The strMemVarName
is the string
name of that node. Save
also has a Boolean flag passed for whether or not sub
objects are to be written. This can be useful in scenarios where you just want to do a shallow printout at that level and not all of the sub
objects below. Now let us take a look at them implemented. The TestObj2
is a class in the unit testing project. Here is the save
and load
methods from that object
.
public override int Save
(ref HtlElement ptrCurrNode, ref string strMemVarName, bool blnWithSubObjects)
{
int intReturn = 0;
if (ptrCurrNode == null) { return 0; };
base.Save(ref ptrCurrNode, ref strMemVarName, blnWithSubObjects);
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);
if (blnWithSubObjects)
{
intReturn &= HtlMemVar.SetMemVar<TestObj01>
(ref ptrCurrNode, "m_myTestObj", ref m_myTestObj, blnWithSubObjects);
};
return intReturn;
}
public override int Load(ref HtlElement ptrCurrNode, ref string strMemVarName)
{
int intReturn = 0;
if (ptrCurrNode == null) { return 0; };
base.Load(ref ptrCurrNode, ref strMemVarName);
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;
}
The first thing that the Save
method does is call the parent class Save
method. Then, it proceeds to set all of the member variables for the class. In this case, there is a bool
, an int
, a double
, a string
, and a sub object of type TestObj01
which also inherits from HtlBase
. Note the TestObj01
is within the Boolean check for print sub object
s. The setting of member variables is achieved by calling the HtlMemVar.SetMemVar<T>()
method. You pass in the reference to the current node, the string
name for that member variable, and the reference to the object. Note all the base object member variables have the blnWithSubObjects
set to false
.
Similarly, the Load
method calls the parent class Load
, and then proceeds to call the reciprocal GetMemVar<T>
function. It should be noted that the reason for having both a Save
and a Load
method is that sometimes the developer wishes to have write only member variables (such as GUID
s for example). The system also works for all of the containers in the HTL. Here is an example of a HtlVector
being serialized.
intReturn &= HtlMemVar.SetMemVar<HtlVector<TestObj01>>
(ref ptrCurrNode, "m_arrObjs", ref m_arrObjs, true);
Once the save
has been called, the user can then serialize with the desired serializer. The following example is using the XDL serializer.
TestObj02 obj = new TestObj02();
string strOut = System.String.Empty;
string strTopName = "rootobject";
HtlXDLWriter writer = new HtlXDLWriter();
HtlElement root = new HtlElement();
obj.Save(ref root, ref strTopName, true);
root.UpdateIndexes();
writer.SaveXDLTree(ref root, ref strOut, true);
System.IO.StreamWriter outfile =
new System.IO.StreamWriter("HtlTestArch_XDL_Obj02Nested.out");
outfile.Write(strOut);
outfile.Close();
obj.m_myBool = false;
obj.m_myInt01 = -1;
obj.m_myDouble04 = -1.0f;
obj.m_myString = "null";
obj.m_myTestObj.Reset();
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 Package
The decision was made to provide wrappers for the Vector
(List
), Map
(Dictionary
), and Queue
classes in the C#.NET library. With these three basic containers, you can cover most of your needs. However, if there is a need for another thread-safe wrapping, they provide a good roadmap to the user on how to create one. As mentioned before, the main intention of the containers (aside from multithreading support) was to integrate it with the archiving system. The included unit tests in the HtlTestSuite
provide sample XML and XDL output. JSON is in the works and should be added soon. Please see the unit tests for the multithreading testing and validation.
HtlRandNumGen Package
There are two random number generators (LCG and Mersenne Twister) and five distributions (HtlUniform
, HtlGamma
, HtlGaussian
, HtlPoisson
, HtlExponential
). Provided are unit tests for Uniform, Exponential, and Gaussian. The RNGs are simple to use. Just create the object, call initialize()
to get your seed, and then call next()
to get the next RNG. HtlUniform
also has the ability to generate RNGs over a range using the intGetNextAB()
or sngGetNextAB()
functions.
HtlGUID Package
There are 64, 128 and 256 bit global unique identifiers available. They inherit from HtlBase
so they are directly serializable. One thing that should be noted is that they are symmetric unlike the windows GUID
class. All segments are equal width. Here is an example of a HtlGUID128
:
975D3F24-F81FF9EB-2F556151-5F9D2204
This makes them simpler to work with and its presentation is neater.
HtlTest Package
The HtlNode
package has a node based architecture similar to the HtlElement
class in the archive package. HtlTestNode
can contain other test nodes and the root node fires all of the children. Refer to the HtlTestSuite
for a good example of its use. Each HtlTestNode
has the following virtual functions that get implemented on demand in child classes. The methods are fired in order in the public PerformTest()
method.
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; }
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.