Introduction
ACF (Another C++ Framework) is a C++ framework designed to bring the power and RAD of the .NET framework to standard C++. ACF version 0.4 added/updated the following features:
1. Simple XML reading and writing
ACF 0.4 supports simple XML reading and writing via XmlTextReader
and XmlTextWriter
classes, which are core XML reading/writing classes in the .NET framework.
XmlTextReader
XmlTextReader
provides fast, forward-only XML reading functionality. The Read
method advances the reader to the next node (element, text, etc.), and the properties (e.g. Name
, Value
) reflect the value of the current node.
For example, given the following XML file (test.xml):
="1.0"
<book>
<title>XML Developer's Guide</title>
<author>Gambardella, Matthew</author>
<price>44.95</price>
<description><![CDATA[ and &.</description>
</book>
The following code reads the XML file and writes the nodes to console:
#include <AcfCorlib.h>
#include <AcfXml.h>
using namespace Acf;
using namespace Acf::Xml;
int main() {
XmlTextReaderPtr reader = new XmlTextReader(str(L"test.xml"));
reader->set_WhitespaceHandling(WhitespaceHandling::None);
while (reader->Read()) {
switch (reader->get_NodeType()) {
case XmlNodeType::XmlDeclaration:
Console::Write(L"<?xml version='1.0'?>");
break;
case XmlNodeType::ProcessingInstruction:
Console::Write(L"<?{0} {1}?>", reader->get_Name(),
reader->get_Value());
break;
case XmlNodeType::Comment:
Console::Write(L"<!--{0}-->", reader->get_Value());
break;
case XmlNodeType::CDATA:
Console::Write(L"<![CDATA[{0}]]>", reader->get_Value());
break;
case XmlNodeType::Element:
if (reader->get_IsEmptyElement())
Console::Write(L"<{0} />", reader->get_Name());
else
Console::Write(L"<{0}>", reader->get_Name());
break;
case XmlNodeType::EndElement:
Console::Write(L"</{0}>", reader->get_Name());
break;
case XmlNodeType::Text:
Console::Write(reader->get_Value());
break;
case XmlNodeType::EntityReference:
Console::Write(reader->get_Name());
break;
}
}
return 0;
}
Internally, XmlTextReader
uses a linked list to store the parsed nodes. The following diagram will help you understand how it works.
There is also a sample application (XmlEditor) which shows how you can use multi-threading and XmlTextReader
to build an interactive document outline. The document outline refreshes in real-time while typing, and when you click a node in the document tree, the corresponding element will be highlighted in the source editor.
XmlTextWriter
XmlTextWriter
provides fast, forward-only XML writing functionality. For example, the following code writes the sample XML to console:
XmlTextWriterPtr writer = new XmlTextWriter(Console::get_Out());
writer->set_Formatting(Formatting::Indented);
writer->WriteStartDocument();
writer->WriteComment(str(L" This is a sample XML document "));
writer->WriteStartElement(str(L"book"));
writer->WriteElementString(str(L"title"), str(L"XML Developer's Guide"));
writer->WriteElementString(str(L"author"), str(L"Gambardella, Matthew"));
writer->WriteElementString(str(L"price"), str(L"44.95"));
writer->WriteStartElement(str(L"description"));
writer->WriteCData(str(L"An in-depth look at creating applications
with XML, using <, >,"));
writer->WriteString(str(L" and &."));
writer->WriteEndElement();
writer->WriteEndElement();
writer->WriteEndDocument();
Please refer to MSDN for detailed description on XmlTextReader
and XmlTextWriter
classes.
2. Threading update
Thread Local Storage (TLS)
ACF 0.4 supports thread local storage (TLS), which is a mechanism to store data that is unique to a thread. To use TLS, first call Thread::AllocateDataSlot
to allocate a new data slot and then use Thread::GetData
/Thread::SetData
to get/set data. Following is an example:
#include <AcfCorlib.h>
using namespace Acf;
using namespace Acf::Threading;
LocalDataStoreSlotPtr _slot = Thread::AllocateDataSlot();
static void ThreadProc() {
ObjectPtr obj = Thread::GetData(_slot);
Thread::SetData(_slot, box(10));
}
int main() {
ObjectPtr obj = new Object();
Thread::SetData(_slot, obj);
ThreadPtr thread = new Thread(ThreadProc);
thread->Start();
thread->Join();
return 0;
}
The TLS implementation in ACF is straightforward and platform-independent: each Thread
object holds an instance TLS map, which stores TLS data. This can be illustrated as follows:
class Thread : public Object {
RefPtr<Dictionary<LocalDataStoreSlot*, ObjectPtr> > _tlsObjects;
static LocalDataStoreSlotPtr AllocateDataSlot() {
return new LocalDataStoreSlot();
}
static ObjectPtr GetData(LocalDataStoreSlot* slot) {
ThreadPtr thread = Thread::get_CurrentThread();
ObjectPtr value = null;
thread->_tlsObjects->TryGetValue(slot, &value);
return value;
}
static void SetData(LocalDataStoreSlot* slot, Object* value) {
ThreadPtr thread = Thread::get_CurrentThread();
thread->_tlsObjects->set_Item(slot, value);
}
};
ThreadPool
ACF 0.4 supports ThreadPool
, which is an easier way to use multiple threads for some tasks. Following is an example:
#include <AcfCorlib.h>
using namespace Acf;
using namespace Acf::Threading;
static void DoWork(Object* state) {
String* s = ref_cast<String*>(state);
Console::WriteLine(s);
}
int main() {
for (int i = 0; i < 3; i++) {
ThreadPool::QueueUserWorkItem(DoWork,
String::Format(L"Hello from work item {0}.", str(i + 1)));
}
Thread::Sleep(1000);
return 0;
}
The ThreadPool
implementation in the CLR is very complex. However, in the .NET compact framework, the ThreadPool
implementation is quite simple: the ThreadPool
class just creates a System.Threading.Timer
to execute each worker delegate asynchronously, and there is no thread management at all. In ACF 0.4, the ThreadPool
implementation uses the timer approach for simplicity, however, this may be changed in future releases.
3. Other updates
ACF 0.4 supports date time formatting (parsing is not supported yet). The following sample application shows the standard formats and custom formats:
There are also other updates, for example, delegates and the Queue<T>
class. ACF 0.4 also removed Visual C++ specific language features, for example, properties, which means p->Text
is now p->get_Text()
. Portability (platform, compiler) will be addressed in future releases.
How to use
- Download and unzip the source files (say C:\acf).
- Setup include and library directories in Visual Studio (requires Visual C++ 2003 or higher).
- Include: C:\acf\src\Corlib and C:\acf\src\Xml.
- Library: C:\acf\lib.
- Open C:\acf\src\acf.sln and build (you can choose debug, release or both).
- Now, it's ready to build other samples or your applications.
Project development
I started this project several months ago with the wish to make it a useful and successful open source C++ framework, and got some good feedback since then. However, it turns out that it's hard for me to keep this project alive and health, mainly because I'm not quite familiar with CVS and Internet-based collaboration, and in recent months I've been busy and don't have good network access. If you are interested in this project, and are familiar with open source project development, please help with this project. Thanks. Suggestions and feedback are also welcome.