diff --git a/Import/Vlpp.h b/Import/Vlpp.h
index 7c3e31a7..e391c29f 100644
--- a/Import/Vlpp.h
+++ b/Import/Vlpp.h
@@ -313,7 +313,7 @@ namespace vl
/// int main()
/// {
/// Ptr boxed = MakePtr>(100);
- /// vint unboxed = boxed.Cast>().UnBox();
+ /// vint unboxed = boxed.Cast>()->Unbox();
/// Console::WriteLine(itow(unboxed));
/// }
/// ]]>
@@ -2840,7 +2840,7 @@ namespace vl
/// is recommended after you don't need any global storages any more, it frees memory.
///
/// data;
/// INITIALIZE_GLOBAL_STORAGE_CLASS
/// data = new vint(100);
@@ -3423,7 +3423,7 @@ Interfaces
virtual void Reset()=0;
/// Test if all values of this enumerator have been evaluated.
/// Returns true if all values have been evaluated.
- /// An evaluated enumerator typically means, there will be no more calculation happens in regardless if all values have been read or not.
+ /// An evaluated enumerator typically means, there will be no more calculation happens in regardless if all values have been read or not.
virtual bool Evaluated()const{return false;}
};
@@ -4962,18 +4962,17 @@ GroupInnerJoin
///
/// Callback that is called when a value in the first group is discarded.
/// This happens for values associated to a key in the first group, that no value is assocated to the same key in the second group.
- /// The first argument is the key, the second argument is the discarded value in the first group.
+ /// The first argument is the key, the second argument is the discarded value list in the first group.
///
///
/// Callback that is called when a value in the second group is discarded.
/// This happens for values associated to a key in the second group, that no value is assocated to the same key in the first group.
- /// The first argument is the key, the second argument is the discarded value in the first group.
+ /// The first argument is the key, the second argument is the discarded value list in the first group.
///
///
/// Callback that is called when a match of values in both groups are found.
/// This happens for any key that, values are associated to this key in both group.
- /// If multiple values are associated to this key in both group, cartesian product applies on values.
- /// The first argument is the key, the second argument is the associated value in the first group, the third argument is the associated value in the second group.
+ /// The first argument is the key, the second argument is the associated value list in the first group, the third argument list is the associated value in the second group.
///
///
/// This function does not change data in provided groups.
@@ -4981,15 +4980,20 @@ GroupInnerJoin
/// & values)
+ /// {
+ /// return L"[" + From(values).Aggregate([](const WString& a, const WString& b) { return a + L", " + b; }) + L"]";
+ /// };
+ ///
/// Group as, bs;
/// as.Add(1 ,L"A"); as.Add(1 ,L"B"); as.Add(2 ,L"C"); as.Add(2 ,L"D");
- /// bs.Add(1 ,L"X"); bs.Add(1 ,L"Y"); as.Add(3 ,L"Z"); as.Add(3 ,L"W");
+ /// bs.Add(1 ,L"X"); bs.Add(1 ,L"Y"); bs.Add(3 ,L"Z"); bs.Add(3 ,L"W");
/// GroupInnerJoin(
/// as,
/// bs,
- /// [](vint key, const WString& value) { Console::WriteLine(L"Discarded in as: " + itow(key) + L", " + value); },
- /// [](vint key, const WString& value) { Console::WriteLine(L"Discarded in bs: " + itow(key) + L", " + value); },
- /// [](vint key, const WString& value1, const WString& value 2) { Console::WriteLine(L"Accepted: " + itow(key) + L", " + value1 + L", " + value2); }
+ /// [&](vint key, const List& values) { Console::WriteLine(L"Discarded in as: " + itow(key) + printList(values)); },
+ /// [&](vint key, const List& values) { Console::WriteLine(L"Discarded in bs: " + itow(key) + printList(values)); },
+ /// [&](vint key, const List& values1, const List& values2) { Console::WriteLine(L"Accepted: " + itow(key) + printList(values1) + printList(values2)); }
/// );
/// }
/// ]]>
@@ -6689,11 +6693,13 @@ LazyList
/// A lazy evaluated container with rich operations. is useful to create lazy list from arrays or containers.
/// The type of elements.
///
- /// A lazy list is usually created directly from a container source, or from a calculation on a source.
- /// Typically the lazy list cannot be used after the source is deleted.
+ /// A lazy list is usually created directly from a container source, or from a calculation on a source.
+ /// Typically the lazy list cannot be used after the source is deleted.
+ ///
/// If this lazy list needs to be used after the source is deleted,
/// you are recommended to use [F:vl.collections.LazyList`1.Evaluate], with forceCopy set to true .
- /// In this way you get a lazy list with all values copied, they do not rely on other objects.
+ ///
+ /// In this way you get a lazy list with all values copied, they do not rely on other objects.
///
template
class LazyList : public Object, public IEnumerable
@@ -7178,7 +7184,7 @@ LazyList
/// {
/// vint xs[] = {1, 2, 3, 4, 5, 6, 7};
/// vint ys[] = {60, 70, 80, 90, 100};
- /// auto zs = From(xs).Pairwise(From(ys)).Select(Pair p){ return p.key + p.value; });
+ /// auto zs = From(xs).Pairwise(From(ys)).Select([](Pair p){ return p.key + p.value; });
/// FOREACH(vint, z, zs) Console::Write(itow(z) + L" ");
/// }
/// ]]>
@@ -7249,12 +7255,12 @@ LazyList
///
/// Set to true to force copying values, regardless of whether this lazy list is evaluated or not.
///
- /// "Evaluated" means reading from this lazy list cause no extra calculation.
- /// In most of the cases, the created lazy list relies on its source.
- /// For example, a lazy list can be created from a reference to a , or from an array on stack.
- /// If this list or array is deleted, then iterating the created lazy list will crash.
- /// By calling the Evaluate function with forceCopy set to true , a new lazy list is created, with all values cached in it.
- /// Its connection to the source list or array is removed, and can then be passed to everywhere.
+ /// "Evaluated" means reading from this lazy list cause no extra calculation.
+ /// In most of the cases, the created lazy list relies on its source.
+ /// For example, a lazy list can be created from a reference to a , or from an array on stack.
+ /// If this list or array is deleted, then iterating the created lazy list will crash.
+ /// By calling the Evaluate function with forceCopy set to true , a new lazy list is created, with all values cached in it.
+ /// Its connection to the source list or array is removed, and can then be passed to everywhere.
///
LazyList Evaluate(bool forceCopy = false)const
{
@@ -7285,7 +7291,7 @@ LazyList
/// auto ys = From(xs).SelectMany([](vint x)
/// {
/// vint factors[] = {1, 10, 100};
- /// return From(factors).Select([](vint f){ return f * x; }).Evaluate(true);
+ /// return From(factors).Select([=](vint f){ return f * x; }).Evaluate(true);
/// });
/// FOREACH(vint, y, ys) Console::Write(itow(y) + L" ");
/// }
@@ -7325,13 +7331,14 @@ LazyList
LazyList>> GroupBy(F f)const
{
typedef FUNCTION_RESULT_TYPE(F) K;
+ auto self = *this;
return Select(f)
.Distinct()
.Select([=](K k)
{
return Pair>(
k,
- Where([=](T t){return k==f(t);})
+ self.Where([=](T t){return k==f(t);})
);
});
}
@@ -7533,19 +7540,50 @@ Partial Ordering
namespace po
{
+ ///
+ /// Node contains extra information for sorted objects.
+ ///
struct Node
{
bool visited = false;
+
+ /// The index used in [F:vl.collections.PartialOrderingProcessor.components], specifying the component that contain this node.
vint component = -1;
- const List* ins = nullptr; // all nodes that this node depends on
- const List* outs = nullptr; // all nodes that depend on this node
- const vint* firstSubClassItem = nullptr; // index of the first item in this sub class node
- vint subClassItemCount = 0; // the number of items in this sub class node
+ /// All nodes that this node depends on.
+ const List* ins = nullptr;
+ /// All nodes that this node is depended by.
+ const List* outs = nullptr;
+ ///
+ /// If [M:vl.collections.PartialOrderingProcessor.InitWithSubClass`2] is used,
+ /// a node becomes a sub class representing objects.
+ /// An object will not be shared by different sub classes.
+ /// In this case, this field is a pointer to an array of indexes of objects.
+ /// The index is used in "items" argument in [M:vl.collections.PartialOrderingProcessor.InitWithSubClass`2]
+ ///
+ const vint* firstSubClassItem = nullptr;
+ ///
+ /// When is available,
+ /// this field is the number of indexes in the array.
+ ///
+ vint subClassItemCount = 0;
};
+ ///
+ /// Component is a unit in sorting result.
+ /// If a component contains more than one node,
+ /// it means that nodes in this component depend on each other by the given relationship.
+ /// It is not possible to tell which node should be place before others for all nodes in this component.
+ /// If all nodes are completely partial ordered,
+ /// there should be only one node in all components.
+ ///
struct Component
{
+ ///
+ /// Pointer to the array of all indexes of nodes in this component.
+ /// Index is used in [F:vl.collections.PartialOrderingProcessor.nodes].
+ ///
const vint* firstNode = nullptr;
+ /// The number of nodes in this component.
vint nodeCount = 0;
};
}
@@ -7554,42 +7592,113 @@ Partial Ordering
namespace collections
{
///
- /// Partial ordering item sorter.
- /// This class sorts items in a partial order using the given dependency information.
- /// Node stored in this class using the index of items.
- /// If a depends on b, then a.ins->Contains(b) && b.outs->Contains(a).
- /// The sorting result is a list of strong connected components in order.
- /// If a depends on b, then the component containing a appears after the component containing b.
- /// Node could represent a sub class if InitWithSubClass is called.
+ /// PartialOrderingProcessor is used to sort objects by given relationships among them.
+ /// The relationship is defined by dependance.
+ /// If A depends on B, then B will be place before A after sorting.
+ /// If a group of objects depends on each other by the given relationship,
+ /// they will be grouped together in the sorting result.
///
class PartialOrderingProcessor : public Object
{
template
using GroupOf = Group;
protected:
- List emptyList;
- Group ins;
- Group outs;
- Array firstNodesBuffer;
- Array subClassItemsBuffer;
+ List emptyList; // make a pointer to an empty list available
+ Group ins; // if a depends on b, ins.Contains(a, b)
+ Group outs; // if a depends on b, outs.Contains(b, a)
+ Array firstNodesBuffer; // one buffer for all Component::firstNode
+ Array subClassItemsBuffer; // one buffer for all Node::firstSubClassItem
void InitNodes(vint itemCount);
void VisitUnvisitedNode(po::Node& node, Array& reversedOrder, vint& used);
void AssignUnassignedNode(po::Node& node, vint componentIndex, vint& used);
public:
- /// Nodes.
+ /// After is called, this field stores all nodes referenced by sorted components.
+ ///
+ /// The same order is kept as the "items" argument in , and .
+ /// If sub classing is enabled by calling ,
+ /// a node represents a sub class of objects.
+ /// In this case, the order in this field does not matter,
+ /// [F:vl.collections.po.Node.firstSubClassItem] stores indexes of objects in this sub class.
+ ///
Array nodes;
- /// Strong connected components in order.
+ /// After is called, this field stores all sorted components in order.
List components;
- /// Sort. This method can only be called once.
+ ///
+ /// Sort objects by given relationships. It will crash if this method is called for more than once.
+ ///
+ ///
+ /// One and only one of , or must be called to set data for sorting.
+ /// And then call to sort objects and store the result in .
+ ///
void Sort();
- /// Initialize the processor, specifying dependency relationships as a group.
- /// Type of the first parameter.
- /// Items.
- /// Dependences. If a depends on b, then depGroups[a].Contains(b) == true.
+ /// Set data for sorting, by providing a list for objects, and a group for their relationship.
+ /// Type of the list for objects. , or are recommended.
+ /// List of objects for sorting.
+ /// Relationship of objects for sorting in . Both keys and values are elements in "items". To say that a depends on b, do depGroup.Add(a, b).
+ /// items;
+ /// items.Add(L"elephant");
+ /// items.Add(L"fish");
+ /// items.Add(L"ball");
+ /// items.Add(L"cat");
+ /// items.Add(L"dog");
+ /// items.Add(L"apple");
+ ///
+ /// Group depGroup;
+ /// depGroup.Add(L"ball", L"apple");
+ /// depGroup.Add(L"cat", L"ball");
+ /// depGroup.Add(L"ball", L"dog");
+ /// depGroup.Add(L"dog", L"cat");
+ /// depGroup.Add(L"elephant", L"cat");
+ /// depGroup.Add(L"fish", L"dog");
+ ///
+ /// PartialOrderingProcessor pop;
+ /// pop.InitWithGroup(items, depGroup);
+ /// pop.Sort();
+ ///
+ /// for (vint i = 0; i < pop.components.Count(); i++)
+ /// {
+ /// auto& c = pop.components[i];
+ /// Console::WriteLine(
+ /// L"Component " + itow(i) + L": " +
+ /// Range(0, c.nodeCount)
+ /// .Select([&](vint ni){ return items[c.firstNode[ni]]; })
+ /// .Aggregate([](const WString& a, const WString& b){ return a + L" " + b; })
+ /// );
+ /// }
+ ///
+ /// for (vint i = 0; i < pop.nodes.Count(); i++)
+ /// {
+ /// auto& n = pop.nodes[i];
+ /// if(n.outs->Count() > 0)
+ /// {
+ /// Console::WriteLine(
+ /// L"Node " + items[i] + L" <- " +
+ /// From(*n.outs)
+ /// .Select([&](vint ni){ return items[ni]; })
+ /// .Aggregate([](const WString& a, const WString& b){ return a + L" " + b; })
+ /// );
+ /// }
+ /// }
+ /// }
+ /// ]]>
template
void InitWithGroup(const TList& items, const GroupOf& depGroup)
{
@@ -7614,11 +7723,75 @@ Partial Ordering
InitNodes(items.Count());
}
- /// Initialize the processor, specifying dependency relationships as a callback function.
- /// Type of the first parameter.
- /// Type of the second parameter.
- /// Items.
- /// Dependences. If a depends on b, then depFunc(a, b) == true.
+ /// Set data for sorting, by providing a list for objects, and a function for their relationship.
+ /// Type of the list for objects. , or are recommended.
+ /// Type of the function that defines relationships of objects.
+ /// List of objects for sorting.
+ /// Relationship of objects for sorting, both arguments are elements in "items". To say that a depends on b, depFunc(a, b) must returns true.
+ /// items;
+ /// items.Add(L"elephant");
+ /// items.Add(L"fish");
+ /// items.Add(L"ball");
+ /// items.Add(L"cat");
+ /// items.Add(L"dog");
+ /// items.Add(L"apple");
+ ///
+ /// auto depFunc = [](const WString& a, const WString& b)
+ /// {
+ /// return
+ /// (a == L"ball" && b == L"apple") ||
+ /// (a == L"cat" && b == L"ball") ||
+ /// (a == L"ball" && b == L"dog") ||
+ /// (a == L"dog" && b == L"cat") ||
+ /// (a == L"elephant" && b == L"cat") ||
+ /// (a == L"fish" && b == L"dog")
+ /// ;
+ /// };
+ ///
+ /// PartialOrderingProcessor pop;
+ /// pop.InitWithFunc(items, depFunc);
+ /// pop.Sort();
+ ///
+ /// for (vint i = 0; i < pop.components.Count(); i++)
+ /// {
+ /// auto& c = pop.components[i];
+ /// Console::WriteLine(
+ /// L"Component " + itow(i) + L": " +
+ /// Range(0, c.nodeCount)
+ /// .Select([&](vint ni){ return items[c.firstNode[ni]]; })
+ /// .Aggregate([](const WString& a, const WString& b){ return a + L" " + b; })
+ /// );
+ /// }
+ ///
+ /// for (vint i = 0; i < pop.nodes.Count(); i++)
+ /// {
+ /// auto& n = pop.nodes[i];
+ /// if(n.outs->Count() > 0)
+ /// {
+ /// Console::WriteLine(
+ /// L"Node " + items[i] + L" <- " +
+ /// From(*n.outs)
+ /// .Select([&](vint ni){ return items[ni]; })
+ /// .Aggregate([](const WString& a, const WString& b){ return a + L" " + b; })
+ /// );
+ /// }
+ /// }
+ /// }
+ /// ]]>
template
void InitWithFunc(const TList& items, TFunc&& depFunc)
{
@@ -7636,12 +7809,100 @@ Partial Ordering
InitWithGroup(items, depGroup);
}
- /// Initialize the processor, specifying dependency relationships and sub class classification as two groups.
- /// Type of the first parameter.
- /// Type of the sub class.
- /// Items.
- /// Dependences. If a depends on b, then depGroups[a].Contains(b) == true.
- /// To put multiple items in a node to represent a sub class, use these items as keys, use a unique value as a value, and put them in subClasses.
+ /// Set data for sorting, by providing a list for objects, and a group for their relationship, and a dictionary for sub classing objects.
+ /// Type of the list for objects. , or are recommended.
+ /// Type of a sub class.
+ /// List of objects for sorting.
+ /// Relationship of objects for sorting in . Both keys and values are elements in "items". To say that a depends on b, do depGroup.Add(a, b).
+ /// Sub classing objects. Keys are elements in "items". If multiple keys have the same value in this dictionary, then these objects are in the same sub class.
+ ///
+ /// Relationships are defined on objects.
+ /// By sub classing objects,
+ /// relationships of sub classes are calculated from "depGroup".
+ /// If object A in sub class X depends on object B in sub class Y, then sub class X depends on sub class Y.
+ /// It is allowed that relatipnships on sub classes are not completely partial ordered,
+ /// in this case, some components may contain multiple sub classes.
+ ///
+ /// items;
+ /// for (vint i = 1; i <= 2; i++)
+ /// {
+ /// items.Add(L"apple_" + itow(i));
+ /// items.Add(L"ball_" + itow(i));
+ /// items.Add(L"cat_" + itow(i));
+ /// items.Add(L"dog_" + itow(i));
+ /// items.Add(L"elephant_" + itow(i));
+ /// items.Add(L"fish_" + itow(i));
+ /// }
+ ///
+ /// Group depGroup;
+ /// depGroup.Add(L"ball_2", L"apple_1");
+ /// depGroup.Add(L"cat_2", L"ball_1");
+ /// depGroup.Add(L"ball_2", L"dog_1");
+ /// depGroup.Add(L"dog_2", L"cat_1");
+ /// depGroup.Add(L"elephant_2", L"cat_1");
+ /// depGroup.Add(L"fish_2", L"dog_1");
+ ///
+ /// Dictionary subClass;
+ /// for (vint i = 1; i <= 2; i++)
+ /// {
+ /// subClass.Add(L"apple_" + itow(i), 1);
+ /// subClass.Add(L"ball_" + itow(i), 2);
+ /// subClass.Add(L"cat_" + itow(i), 3);
+ /// subClass.Add(L"dog_" + itow(i), 4);
+ /// subClass.Add(L"elephant_" + itow(i), 5);
+ /// subClass.Add(L"fish_" + itow(i), 6);
+ /// }
+ ///
+ /// PartialOrderingProcessor pop;
+ /// pop.InitWithSubClass(items, depGroup, subClass);
+ /// pop.Sort();
+ ///
+ /// for (vint i = 0; i < pop.components.Count(); i++)
+ /// {
+ /// auto& c = pop.components[i];
+ /// Console::WriteLine(
+ /// L"Component " + itow(i) + L": sub classes" +
+ /// Range(0, c.nodeCount)
+ /// .Select([&](vint ni) { return c.firstNode[ni]; })
+ /// .Aggregate(L"", [](const WString& a, vint b) { return a + L" " + itow(b); })
+ /// );
+ /// }
+ ///
+ /// for (vint i = 0; i < pop.nodes.Count(); i++)
+ /// {
+ /// auto& n = pop.nodes[i];
+ /// Console::WriteLine(L"Sub class " + itow(i));
+ ///
+ /// Console::WriteLine(
+ /// Range(0, n.subClassItemCount)
+ /// .Select([&](vint si) { return n.firstSubClassItem[si]; })
+ /// .Aggregate(L" :", [&](const WString& a, vint b) { return a + L" " + items[b]; })
+ /// );
+ ///
+ /// if (n.outs->Count() > 0)
+ /// {
+ /// Console::WriteLine(
+ /// From(*n.outs)
+ /// .Aggregate(L" <- sub classes", [](const WString& a, vint b) { return a + L" " + itow(b); })
+ /// );
+ /// }
+ /// }
+ /// }
+ /// ]]>
template
void InitWithSubClass(const TList& items, const GroupOf& depGroup, const Dictionary& subClasses)
{
@@ -7818,22 +8079,22 @@ namespace vl
///
#include
@@ -841,6 +846,11 @@ Folder
/***********************************************************************
.\HTTPUTILITY.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
#ifdef VCZH_MSVC
#include
@@ -855,65 +865,64 @@ namespace vl
HttpRequest
***********************************************************************/
- HttpRequest::HttpRequest()
- :port(0)
- ,secure(false)
- {
- }
-
bool HttpRequest::SetHost(const WString& inputQuery)
{
- server=L"";
- query=L"";
- port=0;
- secure=false;
+ if (method == L"")
+ {
+ method = L"GET";
+ }
+
+ server = L"";
+ query = L"";
+ port = 0;
+ secure = false;
{
- if(server==L"")
+ if (server == L"")
{
- if(inputQuery.Length()>7)
+ if (inputQuery.Length() > 7)
{
- WString protocol=inputQuery.Sub(0, 8);
- if(_wcsicmp(protocol.Buffer(), L"https://")==0)
+ WString protocol = inputQuery.Sub(0, 8);
+ if (_wcsicmp(protocol.Buffer(), L"https://") == 0)
{
- const wchar_t* reading=inputQuery.Buffer()+8;
- const wchar_t* index1=wcschr(reading, L':');
- const wchar_t* index2=wcschr(reading, L'/');
- if(index2)
+ const wchar_t* reading = inputQuery.Buffer() + 8;
+ const wchar_t* index1 = wcschr(reading, L':');
+ const wchar_t* index2 = wcschr(reading, L'/');
+ if (index2)
{
- query=index2;
- server=WString(reading, (index1?index1:index2)-reading);
- port=INTERNET_DEFAULT_HTTPS_PORT;
- secure=true;
- if(index1)
+ query = index2;
+ server = WString(reading, (index1 ? index1 : index2) - reading);
+ port = INTERNET_DEFAULT_HTTPS_PORT;
+ secure = true;
+ if (index1)
{
- WString portString(index1+1, index2-index1-1);
- port=_wtoi(portString.Buffer());
+ WString portString(index1 + 1, index2 - index1 - 1);
+ port = _wtoi(portString.Buffer());
}
return true;
}
}
}
}
- if(server==L"")
+ if (server == L"")
{
- if(inputQuery.Length()>6)
+ if (inputQuery.Length() > 6)
{
- WString protocol=inputQuery.Sub(0, 7);
- if(_wcsicmp(protocol.Buffer(), L"http://")==0)
+ WString protocol = inputQuery.Sub(0, 7);
+ if (_wcsicmp(protocol.Buffer(), L"http://") == 0)
{
- const wchar_t* reading=inputQuery.Buffer()+7;
- const wchar_t* index1=wcschr(reading, L':');
- const wchar_t* index2=wcschr(reading, L'/');
- if(index2)
+ const wchar_t* reading = inputQuery.Buffer() + 7;
+ const wchar_t* index1 = wcschr(reading, L':');
+ const wchar_t* index2 = wcschr(reading, L'/');
+ if (index2)
{
- query=index2;
- server=WString(reading, (index1?index1:index2)-reading);
- port=INTERNET_DEFAULT_HTTP_PORT;
- if(index1)
+ query = index2;
+ server = WString(reading, (index1 ? index1 : index2) - reading);
+ port = INTERNET_DEFAULT_HTTP_PORT;
+ if (index1)
{
- WString portString(index1+1, index2-index1-1);
- port=_wtoi(portString.Buffer());
+ WString portString(index1 + 1, index2 - index1 - 1);
+ port = _wtoi(portString.Buffer());
}
return true;
}
@@ -926,9 +935,9 @@ HttpRequest
void HttpRequest::SetBodyUtf8(const WString& bodyString)
{
- vint utf8Size=WideCharToMultiByte(CP_UTF8, 0, bodyString.Buffer(), (int)bodyString.Length(), NULL, 0, NULL, NULL);
- char* utf8=new char[utf8Size+1];
- ZeroMemory(utf8, utf8Size+1);
+ vint utf8Size = WideCharToMultiByte(CP_UTF8, 0, bodyString.Buffer(), (int)bodyString.Length(), NULL, 0, NULL, NULL);
+ char* utf8 = new char[utf8Size + 1];
+ ZeroMemory(utf8, utf8Size + 1);
WideCharToMultiByte(CP_UTF8, 0, bodyString.Buffer(), (int)bodyString.Length(), utf8, (int)utf8Size, NULL, NULL);
body.Resize(utf8Size);
@@ -940,21 +949,16 @@ HttpRequest
HttpResponse
***********************************************************************/
- HttpResponse::HttpResponse()
- :statusCode(0)
- {
- }
-
WString HttpResponse::GetBodyUtf8()
{
WString response;
- char* utf8=&body[0];
- vint totalSize=body.Count();
- vint utf16Size=MultiByteToWideChar(CP_UTF8, 0, utf8, (int)totalSize, NULL, 0);
- wchar_t* utf16=new wchar_t[utf16Size+1];
- ZeroMemory(utf16, (utf16Size+1)*sizeof(wchar_t));
+ char* utf8 = &body[0];
+ vint totalSize = body.Count();
+ vint utf16Size = MultiByteToWideChar(CP_UTF8, 0, utf8, (int)totalSize, NULL, 0);
+ wchar_t* utf16 = new wchar_t[utf16Size + 1];
+ ZeroMemory(utf16, (utf16Size + 1) * sizeof(wchar_t));
MultiByteToWideChar(CP_UTF8, 0, utf8, (int)totalSize, utf16, (int)utf16Size);
- response=utf16;
+ response = utf16;
delete[] utf16;
return response;
}
@@ -970,117 +974,117 @@ Utilities
BufferPair()
:buffer(0)
- ,length(0)
+ , length(0)
{
}
BufferPair(char* _buffer, vint _length)
:buffer(_buffer)
- ,length(_length)
+ , length(_length)
{
}
- bool operator==(const BufferPair& pair){return false;}
- bool operator!=(const BufferPair& pair){return true;}
+ bool operator==(const BufferPair& pair) { return false; }
+ bool operator!=(const BufferPair& pair) { return true; }
};
bool HttpQuery(const HttpRequest& request, HttpResponse& response)
{
// initialize
- response.statusCode=-1;
- HINTERNET internet=NULL;
- HINTERNET connectedInternet=NULL;
- HINTERNET requestInternet=NULL;
- BOOL httpResult=FALSE;
- DWORD error=0;
+ response.statusCode = -1;
+ HINTERNET internet = NULL;
+ HINTERNET connectedInternet = NULL;
+ HINTERNET requestInternet = NULL;
+ BOOL httpResult = FALSE;
+ DWORD error = 0;
List acceptTypes;
List availableBuffers;
// access http
- internet=WinHttpOpen(L"vczh", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0);
- error=GetLastError();
- if(!internet) goto CLEANUP;
+ internet = WinHttpOpen(L"vczh", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0);
+ error = GetLastError();
+ if (!internet) goto CLEANUP;
// connect
- connectedInternet=WinHttpConnect(internet, request.server.Buffer(), (int)request.port, 0);
- error=GetLastError();
- if(!connectedInternet) goto CLEANUP;
+ connectedInternet = WinHttpConnect(internet, request.server.Buffer(), (int)request.port, 0);
+ error = GetLastError();
+ if (!connectedInternet) goto CLEANUP;
// open request
- for(vint i=0;i0)
+ // extra headers
+ for (int i = 0; i < request.extraHeaders.Count(); i++)
{
- httpResult=WinHttpSendRequest(requestInternet, WINHTTP_NO_ADDITIONAL_HEADERS, 0, (LPVOID)&request.body.Get(0), (int)request.body.Count(), (int)request.body.Count(), NULL);
+ WString key = request.extraHeaders.Keys()[i];
+ WString value = request.extraHeaders.Values().Get(i);
+ WinHttpAddRequestHeaders(requestInternet, (key + L":" + value).Buffer(), -1, WINHTTP_ADDREQ_FLAG_REPLACE | WINHTTP_ADDREQ_FLAG_ADD);
+ }
+
+ if (request.body.Count() > 0)
+ {
+ httpResult = WinHttpSendRequest(requestInternet, WINHTTP_NO_ADDITIONAL_HEADERS, 0, (LPVOID)&request.body.Get(0), (int)request.body.Count(), (int)request.body.Count(), NULL);
}
else
{
- httpResult=WinHttpSendRequest(requestInternet, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, NULL);
+ httpResult = WinHttpSendRequest(requestInternet, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, NULL);
}
- error=GetLastError();
- if(httpResult==FALSE) goto CLEANUP;
+ error = GetLastError();
+ if (httpResult == FALSE) goto CLEANUP;
// receive response
- httpResult=WinHttpReceiveResponse(requestInternet, NULL);
- error=GetLastError();
- if(httpResult!=TRUE) goto CLEANUP;
+ httpResult = WinHttpReceiveResponse(requestInternet, NULL);
+ error = GetLastError();
+ if (httpResult != TRUE) goto CLEANUP;
// read response status code
{
- DWORD headerLength=sizeof(DWORD);
- DWORD statusCode=0;
- httpResult=WinHttpQueryHeaders(requestInternet, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &statusCode, &headerLength, WINHTTP_NO_HEADER_INDEX);
- error=GetLastError();
- if(httpResult==FALSE) goto CLEANUP;
- response.statusCode=statusCode;
+ DWORD headerLength = sizeof(DWORD);
+ DWORD statusCode = 0;
+ httpResult = WinHttpQueryHeaders(requestInternet, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &statusCode, &headerLength, WINHTTP_NO_HEADER_INDEX);
+ error = GetLastError();
+ if (httpResult == FALSE) goto CLEANUP;
+ response.statusCode = statusCode;
}
// read respons cookie
{
- DWORD headerLength=sizeof(DWORD);
- httpResult=WinHttpQueryHeaders(requestInternet, WINHTTP_QUERY_RAW_HEADERS_CRLF, WINHTTP_HEADER_NAME_BY_INDEX, NULL, &headerLength, WINHTTP_NO_HEADER_INDEX);
- error=GetLastError();
- if(error==ERROR_INSUFFICIENT_BUFFER)
+ DWORD headerLength = sizeof(DWORD);
+ httpResult = WinHttpQueryHeaders(requestInternet, WINHTTP_QUERY_RAW_HEADERS_CRLF, WINHTTP_HEADER_NAME_BY_INDEX, NULL, &headerLength, WINHTTP_NO_HEADER_INDEX);
+ error = GetLastError();
+ if (error == ERROR_INSUFFICIENT_BUFFER)
{
- wchar_t* rawHeader=new wchar_t[headerLength/sizeof(wchar_t)];
+ wchar_t* rawHeader = new wchar_t[headerLength / sizeof(wchar_t)];
ZeroMemory(rawHeader, headerLength);
- httpResult=WinHttpQueryHeaders(requestInternet, WINHTTP_QUERY_RAW_HEADERS_CRLF, WINHTTP_HEADER_NAME_BY_INDEX, rawHeader, &headerLength, WINHTTP_NO_HEADER_INDEX);
-
- const wchar_t* cookieStart=wcsstr(rawHeader, L"Cookie:");
- if(cookieStart)
+ httpResult = WinHttpQueryHeaders(requestInternet, WINHTTP_QUERY_RAW_HEADERS_CRLF, WINHTTP_HEADER_NAME_BY_INDEX, rawHeader, &headerLength, WINHTTP_NO_HEADER_INDEX);
+
+ const wchar_t* cookieStart = wcsstr(rawHeader, L"Cookie:");
+ if (cookieStart)
{
- const wchar_t* cookieEnd=wcsstr(cookieStart, L";");
- if(cookieEnd)
+ const wchar_t* cookieEnd = wcsstr(cookieStart, L";");
+ if (cookieEnd)
{
- response.cookie=WString(cookieStart+7, cookieEnd-cookieStart-7);
+ response.cookie = WString(cookieStart + 7, cookieEnd - cookieStart - 7);
}
}
delete[] rawHeader;
@@ -1088,18 +1092,18 @@ Utilities
}
// read response body
- while(true)
+ while (true)
{
- DWORD bytesAvailable=0;
- BOOL queryDataAvailableResult=WinHttpQueryDataAvailable(requestInternet, &bytesAvailable);
- error=GetLastError();
- if(queryDataAvailableResult==TRUE && bytesAvailable!=0)
+ DWORD bytesAvailable = 0;
+ BOOL queryDataAvailableResult = WinHttpQueryDataAvailable(requestInternet, &bytesAvailable);
+ error = GetLastError();
+ if (queryDataAvailableResult == TRUE && bytesAvailable != 0)
{
- char* utf8=new char[bytesAvailable];
- DWORD bytesRead=0;
- BOOL readDataResult=WinHttpReadData(requestInternet, utf8, bytesAvailable, &bytesRead);
- error=GetLastError();
- if(readDataResult==TRUE)
+ char* utf8 = new char[bytesAvailable];
+ DWORD bytesRead = 0;
+ BOOL readDataResult = WinHttpReadData(requestInternet, utf8, bytesAvailable, &bytesRead);
+ error = GetLastError();
+ if (readDataResult == TRUE)
{
availableBuffers.Add(BufferPair(utf8, bytesRead));
}
@@ -1142,40 +1146,40 @@ Utilities
}
}
CLEANUP:
- if(requestInternet) WinHttpCloseHandle(requestInternet);
- if(connectedInternet) WinHttpCloseHandle(connectedInternet);
- if(internet) WinHttpCloseHandle(internet);
- return response.statusCode!=-1;
+ if (requestInternet) WinHttpCloseHandle(requestInternet);
+ if (connectedInternet) WinHttpCloseHandle(connectedInternet);
+ if (internet) WinHttpCloseHandle(internet);
+ return response.statusCode != -1;
}
WString UrlEncodeQuery(const WString& query)
{
- vint utf8Size=WideCharToMultiByte(CP_UTF8, 0, query.Buffer(),(int) query.Length(), NULL, 0, NULL, NULL);
- char* utf8=new char[utf8Size+1];
- ZeroMemory(utf8, utf8Size+1);
+ vint utf8Size = WideCharToMultiByte(CP_UTF8, 0, query.Buffer(), (int)query.Length(), NULL, 0, NULL, NULL);
+ char* utf8 = new char[utf8Size + 1];
+ ZeroMemory(utf8, utf8Size + 1);
WideCharToMultiByte(CP_UTF8, 0, query.Buffer(), (int)query.Length(), utf8, (int)utf8Size, NULL, NULL);
- wchar_t* encoded=new wchar_t[utf8Size*3+1];
- ZeroMemory(encoded, (utf8Size*3+1)*sizeof(wchar_t));
- wchar_t* writing=encoded;
- for(vint i=0;i
@@ -1851,6 +1860,11 @@ Locale
/***********************************************************************
.\THREADING.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
#ifdef VCZH_MSVC
namespace vl
@@ -2842,6 +2856,11 @@ namespace vl
/***********************************************************************
.\THREADINGLINUX.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
#ifdef VCZH_GCC
#include
#include
@@ -3759,6 +3778,11 @@ ThreadLocalStorage
/***********************************************************************
.\STREAM\ACCESSOR.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
#include
namespace vl
@@ -4346,6 +4370,11 @@ DecoderStream
/***********************************************************************
.\STREAM\BROADCASTSTREAM.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -4440,7 +4469,8 @@ BroadcastStream
{
for(vint i=0;iWrite(_buffer, _size);
+ vint written = streams[i]->Write(_buffer, _size);
+ CHECK_ERROR(written == _size, L"BroadcastStream::Write(void*, vint)#Failed to copy data to the output stream.");
}
position+=_size;
return _size;
@@ -4456,6 +4486,11 @@ BroadcastStream
/***********************************************************************
.\STREAM\CACHESTREAM.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -4760,6 +4795,11 @@ CacheStream
/***********************************************************************
.\STREAM\CHARFORMAT.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
#if defined VCZH_MSVC
#include
#elif defined VCZH_GCC
@@ -5861,6 +5901,11 @@ CharEncoder
/***********************************************************************
.\STREAM\COMPRESSIONSTREAM.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -6301,6 +6346,11 @@ Helper Functions
/***********************************************************************
.\STREAM\FILESTREAM.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
#if defined VCZH_GCC
#endif
@@ -6529,6 +6579,11 @@ FileStream
/***********************************************************************
.\STREAM\MEMORYSTREAM.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -6704,6 +6759,11 @@ MemoryStream
/***********************************************************************
.\STREAM\MEMORYWRAPPERSTREAM.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -6850,6 +6910,11 @@ MemoryWrapperStream
/***********************************************************************
.\STREAM\RECORDERSTREAM.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -6861,7 +6926,7 @@ RecorderStream
RecorderStream::RecorderStream(IStream& _in, IStream& _out)
:in(&_in)
- ,out(&_out)
+ , out(&_out)
{
}
@@ -6896,23 +6961,23 @@ RecorderStream
bool RecorderStream::IsAvailable()const
{
- return in!=0 && out!=0 && in->IsAvailable() && out->IsAvailable();
+ return in != 0 && out != 0 && in->IsAvailable() && out->IsAvailable();
}
void RecorderStream::Close()
{
- in=0;
- out=0;
+ in = nullptr;
+ out = nullptr;
}
pos_t RecorderStream::Position()const
{
- return IsAvailable()?in->Position():-1;
+ return IsAvailable() ? in->Position() : -1;
}
pos_t RecorderStream::Size()const
{
- return IsAvailable()?in->Size():-1;
+ return IsAvailable() ? in->Size() : -1;
}
void RecorderStream::Seek(pos_t _size)
@@ -6932,8 +6997,9 @@ RecorderStream
vint RecorderStream::Read(void* _buffer, vint _size)
{
- _size=in->Read(_buffer, _size);
- out->Write(_buffer, _size);
+ _size = in->Read(_buffer, _size);
+ vint written = out->Write(_buffer, _size);
+ CHECK_ERROR(written == _size, L"RecorderStream::Read(void*, vint)#Failed to copy data to the output stream.");
return _size;
}
diff --git a/Import/VlppOS.h b/Import/VlppOS.h
index a8c40fb9..011a0322 100644
--- a/Import/VlppOS.h
+++ b/Import/VlppOS.h
@@ -7,6 +7,11 @@ DEVELOPER: Zihan Chen(vczh)
/***********************************************************************
.\HTTPUTILITY.H
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
#ifndef VCZH_HTTPUTILITY
#define VCZH_HTTPUTILITY
@@ -20,7 +25,7 @@ namespace vl
HTTP Utility
***********************************************************************/
- /// A type representing an http requiest.
+ /// An http requiest.
class HttpRequest
{
typedef collections::Array BodyBuffer;
@@ -30,37 +35,37 @@ HTTP Utility
/// Name of the server, like "gaclib.net".
WString server;
/// Port of the server, like 80.
- vint port;
- /// Query of the request, like "/GettingStart.html".
+ vint port = 0;
+ /// Query of the request, like "/index.html".
WString query;
- /// Set to true if the request uses SSL.
- bool secure;
- /// User name to authorize. Set to empty if you don't want to provide it.
+ /// Set to true if the request uses SSL, or https.
+ bool secure = false;
+ /// User name to authorize. Set to empty if authorization is not needed.
WString username;
- /// Password to authorize. Set to empty if you don't want to provide it.
+ /// Password to authorize. Set to empty if authorization is not needed.
WString password;
/// HTTP method, like "GET", "POST", "PUT", "DELETE", etc.
WString method;
- /// Cookie. Set to empty if you don't want to provide it.
+ /// Cookie. Set to empty if cookie is not needed.
WString cookie;
- /// Request body. This is a binary array using an array container to char.
+ /// Request body. This is a byte array.
BodyBuffer body;
/// Content type, like "text/xml".
WString contentType;
- /// Accept type list, elements of it like "text/xml".
+ /// Accept type list, elements like "text/xml".
StringList acceptTypes;
/// A dictionary to contain extra headers.
HeaderMap extraHeaders;
/// Create an empty request.
- HttpRequest();
+ HttpRequest() = default;
/// Set , , and fields for you using an URL.
/// Returns true if this operation succeeded.
/// The URL.
bool SetHost(const WString& inputQuery);
- /// Fill the body with a text using UTF-8 encoding.
+ /// Fill the text body in UTF-8.
/// The text to fill.
void SetBodyUtf8(const WString& bodyString);
};
@@ -71,28 +76,57 @@ HTTP Utility
typedef collections::Array BodyBuffer;
public:
/// Status code, like 200.
- vint statusCode;
- /// Response body. This is a binary array using an array container to char.
+ vint statusCode = 0;
+ /// Response body. This is a byte array.
BodyBuffer body;
/// Returned cookie from the server.
WString cookie;
- HttpResponse();
+ HttpResponse() = default;
- /// If you believe the server returns a text in UTF-8, use it to decode the body.
+ /// Get the text body, encoding is assumed to be UTF-8.
/// The response body as text.
WString GetBodyUtf8();
};
/// Send an http request and receive a response.
- /// Returns true if this operation succeeded. Even the server returns 404 will be treated as success, because you get the response.
- /// The request.
- /// The response.
+ /// Returns true if this operation succeeded, even when the server returns 404.
+ /// The request to send.
+ /// Returns the response.
+ ///
+ ///
+ /// This function will block the calling thread until the respons is returned.
+ ///
+ ///
+ /// This function is only available in Windows.
+ ///
+ ///
+ ///
extern bool HttpQuery(const HttpRequest& request, HttpResponse& response);
/// Encode a text as part of the url. This function can be used to create arguments in an URL.
/// The encoded text.
/// The text to encode.
+ ///
+ ///
+ /// When a character is not a digit or a letter,
+ /// it is first encoded to UTF-8,
+ /// then each byte is written as "%" with two hex digits.
+ ///
+ ///
+ /// This function is only available in Windows.
+ ///
+ ///
extern WString UrlEncodeQuery(const WString& query);
}
@@ -105,11 +139,8 @@ HTTP Utility
.\LOCALE.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Framework::Locale
-
-Interfaces:
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_LOCALE
@@ -119,12 +150,31 @@ Interfaces:
namespace vl
{
/// Locale awared operations. Macro "INVLOC" is a shortcut to get a invariant locale.
+ ///
+ ///
+ /// For all string operations that the normalization does not set to None ,
+ /// and all non-string operations,
+ /// the result is platform-dependent.
+ /// This class is designed to process human-readable text,
+ /// do not rely on the result.
+ ///
+ ///
+ /// In Linux and macOS, only en-US is supported, with a hard-coded set of date and time formats,
+ /// and string operations only support None and IgnoreCase for normalization.
+ ///
+ ///
class Locale : public Object
{
protected:
WString localeName;
public:
+ /// Create a locale with a specified local name.
+ /// The name of the locale. If it is not provided, it becomes the invariant locale.
+ ///
+ /// In Windows, the specified locale need to be installed in order to take effect.
+ /// In Linux and macOS, only en-US is supported.
+ ///
Locale(const WString& _localeName=WString::Empty);
~Locale();
@@ -135,72 +185,89 @@ namespace vl
bool operator>(const Locale& value)const { return localeName>value.localeName; }
bool operator>=(const Locale& value)const { return localeName>=value.localeName; }
- /// Get the invariant locale.
+ /// Get the invariant locale. An invariant locale is neutral, it is not awared of any language specified thing.
/// The invariant locale.
static Locale Invariant();
/// Get the system default locale. This locale controls the code page that used by the the system to interpret ANSI string buffers.
/// The system default locale.
static Locale SystemDefault();
- /// Get the user default locale. This locale reflect the user's setting.
+ /// Get the user default locale. This locale reflect the user's settings and UI language.
/// The user default locale.
static Locale UserDefault();
/// Get all supported locales.
/// All supported locales.
static void Enumerate(collections::List& locales);
- /// Get the name of the locale.
- /// The name of the locale.
+ /// Get the name of this locale.
+ /// The name of this locale.
const WString& GetName()const;
- /// Get all short date formats for the locale.
- /// The formats.
+ /// Get all short date formats for this locale.
+ /// Returns all formats.
void GetShortDateFormats(collections::List& formats)const;
- /// Get all long date formats for the locale.
- /// The formats.
+ /// Get all long date formats for this locale.
+ /// Returns all formats.
void GetLongDateFormats(collections::List& formats)const;
- /// Get all Year-Month date formats for the locale.
- /// The formats.
+ /// Get all Year-Month date formats for this locale.
+ /// Returns all formats.
void GetYearMonthDateFormats(collections::List& formats)const;
- /// Get all long time formats for the locale.
- /// The formats.
+ /// Get all long time formats for this locale.
+ /// Returns all formats.
void GetLongTimeFormats(collections::List& formats)const;
- /// Get all short time formats for the locale.
- /// The formats.
+ /// Get all short time formats for this locale.
+ /// Returns all formats.
void GetShortTimeFormats(collections::List& formats)const;
/// Convert a date to a formatted string.
/// The formatted string.
/// The format to use.
/// The date to convert.
+ ///
+ /// The value of the "format" argument must come from any of the following functions.
+ /// Otherwise the behavior is undefined.
+ ///
+ ///
WString FormatDate(const WString& format, DateTime date)const;
/// Convert a time to a formatted string.
/// The formatted string.
/// The format to use.
/// The time to convert.
+ ///
+ /// The value of the "format" argument must come from any of the following functions.
+ /// Otherwise the behavior is undefined.
+ ///
+ ///
WString FormatTime(const WString& format, DateTime time)const;
- /// Convert a number to a formatted string.
+ /// Convert a number to a formatted string according to the locale.
/// The formatted string.
/// The number to convert.
WString FormatNumber(const WString& number)const;
- /// Convert a currency (money) to a formatted string.
+ /// Convert a currency (money) to a formatted string according to the locale.
/// The formatted string.
/// The currency to convert.
WString FormatCurrency(const WString& currency)const;
- /// Get the short display string of a day of week.
+ /// Get the short display string of a day of week according to the locale.
/// The display string.
/// Day of week, begins from 0 as Sunday.
WString GetShortDayOfWeekName(vint dayOfWeek)const;
- /// Get the long display string of a day of week.
+ /// Get the long display string of a day of week according to the locale.
/// The display string.
/// Day of week, begins from 0 as Sunday.
WString GetLongDayOfWeekName(vint dayOfWeek)const;
- /// Get the short display string of a month.
+ /// Get the short display string of a month according to the locale.
/// The display string.
/// Month, begins from 1 as January.
WString GetShortMonthName(vint month)const;
- /// Get the long display string of a month.
+ /// Get the long display string of a month according to the locale.
/// The display string.
/// Month, begins from 1 as January.
WString GetLongMonthName(vint month)const;
@@ -209,18 +276,22 @@ namespace vl
/// Convert characters to the full width.
/// The converted string.
/// The string to convert.
+ /// This function is only available in Windows.
WString ToFullWidth(const WString& str)const;
/// Convert characters to the half width.
/// The converted string.
/// The string to convert.
+ /// This function is only available in Windows.
WString ToHalfWidth(const WString& str)const;
/// Convert characters to the Hiragana.
/// The converted string.
/// The string to convert.
+ /// This function is only available in Windows.
WString ToHiragana(const WString& str)const;
/// Convert characters to the Katagana.
/// The converted string.
/// The string to convert.
+ /// This function is only available in Windows.
WString ToKatagana(const WString& str)const;
#endif
@@ -245,14 +316,17 @@ namespace vl
/// Convert characters to Simplified Chinese.
/// The converted string.
/// The string to convert.
+ /// This function is only available in Windows.
WString ToSimplifiedChinese(const WString& str)const;
/// Convert characters to the Traditional Chinese.
/// The converted string.
/// The string to convert.
+ /// This function is only available in Windows.
WString ToTraditionalChinese(const WString& str)const;
/// Convert characters to the tile case, in which the first letter of each major word is capitalized.
/// The converted string.
/// The string to convert.
+ /// This function is only available in Windows.
WString ToTileCase(const WString& str)const;
#endif
@@ -264,19 +338,19 @@ namespace vl
/// Ignore case using the file system rule.
IgnoreCase=1,
#ifdef VCZH_MSVC
- /// Ignore case using the linguistic rule.
+ /// Ignore case using the linguistic rule. This value is only available in Windows.
IgnoreCaseLinguistic=2,
- /// Ignore the difference between between hiragana and katakana characters.
+ /// Ignore the difference between between hiragana and katakana characters. This value is only available in Windows.
IgnoreKanaType=4,
- /// Ignore nonspacing characters.
+ /// Ignore nonspacing characters. This value is only available in Windows.
IgnoreNonSpace=8,
- /// Ignore symbols and punctuation.
+ /// Ignore symbols and punctuation. This value is only available in Windows.
IgnoreSymbol=16,
- /// Ignore the difference between half-width and full-width characters.
+ /// Ignore the difference between half-width and full-width characters. This value is only available in Windows.
IgnoreWidth=32,
- /// Treat digits as numbers during sorting.
+ /// Treat digits as numbers during sorting. This value is only available in Windows.
DigitsAsNumbers=64,
- /// Treat punctuation the same as symbols.
+ /// Treat punctuation the same as symbols. This value is only available in Windows.
StringSoft=128,
#endif
};
@@ -298,28 +372,32 @@ namespace vl
/// The second string to compare.
vint CompareOrdinalIgnoreCase(const WString& s1, const WString& s2)const;
/// Find the first position that the sub string appears in a text.
- /// Returns a pair of numbers, the first number indicating the position in the text, the second number indicating the size of the equivalence sub string in the text. For some normalization, the found sub string may be binary different to the string you want to find.
+ /// Returns a pair of numbers, the first number indicating the position in the text, the second number indicating the size of the equivalence sub string in the text.
/// The text to find the sub string.
/// The sub string to match.
/// Flags controlling how to normalize a string.
+ /// For any normalization that is not None , the found sub string could be different to the string you want to find.
collections::Pair FindFirst(const WString& text, const WString& find, Normalization normalization)const;
/// Find the last position that the sub string appears in a text.
- /// Returns a pair of numbers, the first number indicating the position in the text, the second number indicating the size of the equivalence sub string in the text. For some normalization, the found sub string may be binary different to the string you want to find.
+ /// Returns a pair of numbers, the first number indicating the position in the text, the second number indicating the size of the equivalence sub string in the text.
/// The text to find the sub string.
/// The sub string to match.
/// Flags controlling how to normalize a string.
+ /// For any normalization that is not None , the found sub string could be different to the string you want to find.
collections::Pair FindLast(const WString& text, const WString& find, Normalization normalization)const;
/// Test is the prefix of the text equivalence to the provided sub string.
/// Returns true if the prefix of the text equivalence to the provided sub string.
/// The text to test the prefix.
/// The sub string to match.
/// Flags controlling how to normalize a string.
+ /// For any normalization that is not None , the found prefix could be different to the string you want to find.
bool StartsWith(const WString& text, const WString& find, Normalization normalization)const;
/// Test is the postfix of the text equivalence to the provided sub string.
/// Returns true if the postfix of the text equivalence to the provided sub string.
/// The text to test the postfix.
/// The sub string to match.
/// Flags controlling how to normalize a string.
+ /// For any normalization that is not None , the postfix could be different to the string you want to find.
bool EndsWith(const WString& text, const WString& find, Normalization normalization)const;
};
@@ -332,16 +410,8 @@ namespace vl
.\THREADING.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Framework::Threading
-
-Classes:
- Thread : Thread
- CriticalSection
- Mutex
- Semaphore
- EventObject
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_THREADING
@@ -378,47 +448,53 @@ Kernel Mode Objects
WaitableObject();
void SetData(threading_internal::WaitableData* data);
public:
- /// Test if the object has already been created. Some of the synchronization objects should initialize itself after the constructor. This function is only available in Windows.
+ /// Test if the object has already been created. Some of the synchronization objects should initialize itself after the constructor.
/// Returns true if the object has already been created.
+ /// This function is only available in Windows.
bool IsCreated();
/// Wait for this object to signal.
/// Returns true if the object is signaled. Returns false if this operation failed.
bool Wait();
- /// Wait for this object to signal for a period of time. This function is only available in Windows.
+ /// Wait for this object to signal for a period of time.
/// Returns true if the object is signaled. Returns false if this operation failed, including time out.
/// Time in milliseconds.
+ /// This function is only available in Windows.
bool WaitForTime(vint ms);
- /// Wait for multiple objects. This function is only available in Windows.
+ /// Wait for multiple objects.
/// Returns true if all objects are signaled. Returns false if this operation failed.
/// A pointer to an array to pointers.
/// The number of objects in the array.
+ /// This function is only available in Windows.
static bool WaitAll(WaitableObject** objects, vint count);
- /// Wait for multiple objects for a period of time. This function is only available in Windows.
+ /// Wait for multiple objects for a period of time.
/// Returns true if all objects are signaled. Returns false if this operation failed, including time out.
/// A pointer to an array to pointers.
/// The number of objects in the array.
/// Time in milliseconds.
+ /// This function is only available in Windows.
static bool WaitAllForTime(WaitableObject** objects, vint count, vint ms);
- /// Wait for one of the objects. This function is only available in Windows.
+ /// Wait for one of the objects.
/// Returns the index of the first signaled or abandoned object, according to the "abandoned" parameter. Returns -1 if this operation failed.
/// A pointer to an array to pointers.
/// The number of objects in the array.
/// Returns true if the waiting is canceled by an abandoned object. An abandoned object is caused by it's owner thread existing without releasing it.
+ /// This function is only available in Windows.
static vint WaitAny(WaitableObject** objects, vint count, bool* abandoned);
- /// Wait for one of the objects for a period of time. This function is only available in Windows.
+ /// Wait for one of the objects for a period of time.
/// Returns the index of the first signaled or abandoned object, according to the "abandoned" parameter. Returns -1 if this operation failed, including time out.
/// A pointer to an array to pointers.
/// The number of objects in the array.
/// Time in milliseconds.
/// Returns true if the waiting is canceled by an abandoned object. An abandoned object is caused by it's owner thread existing without releasing it.
+ /// This function is only available in Windows.
static vint WaitAnyForTime(WaitableObject** objects, vint count, vint ms, bool* abandoned);
#elif defined VCZH_GCC
virtual bool Wait() = 0;
#endif
};
- /// Representing a thread. [M:vl.Thread.CreateAndStart] is the suggested way to create threads.
+ /// Thread. [M:vl.Thread.CreateAndStart] is the suggested way to create threads.
class Thread : public WaitableObject
{
friend void InternalThreadProc(Thread* thread);
@@ -449,12 +525,12 @@ Kernel Mode Objects
/// Returns the created thread.
/// The function pointer.
/// The argument to call the function pointer.
- /// Set to true (by default) to make the thread delete itself after the job is done. If you set this argument to true, you are not suggested to touch the returned thread pointer in any way.
+ /// Set to true (by default) to make the thread delete itself after the job is done. If you set this argument to true, you are not recommended to touch the returned thread pointer in any way.
static Thread* CreateAndStart(ThreadProcedure procedure, void* argument=0, bool deleteAfterStopped=true);
/// Create a thread using a function object or a lambda expression.
/// Returns the created thread.
/// The function object or the lambda expression.
- /// Set to true (by default) to make the thread delete itself after the job is done. If you set this argument to true, you are not suggested to touch the returned thread pointer in any way.
+ /// Set to true (by default) to make the thread delete itself after the job is done. If you set this argument to true, you are not recommended to touch the returned thread pointer in any way.
static Thread* CreateAndStart(const Func& procedure, bool deleteAfterStopped=true);
/// Pause the caller thread for a period of time.
/// Time in milliseconds.
@@ -483,7 +559,7 @@ Kernel Mode Objects
#endif
};
- /// Mutex.
+ /// Mutex. or is required to initialize a mutex.
class Mutex : public WaitableObject
{
private:
@@ -500,12 +576,12 @@ Kernel Mode Objects
/// Open an existing global named mutex.
/// Returns true if this operation succeeded.
/// Set to true make the mutex visible to all all child processes. This argument is only used in Windows.
- /// Name of the mutex. This argument is ignored in Linux.
+ /// Name of the mutex.
bool Open(bool inheritable, const WString& name);
///
/// Release the mutex.
- /// In the implementation for Linux, calling Release() more than once between two Wait(), or calling Wait() more than once between two Release(), will results in an undefined behavior.
+ /// In Linux, calling Release() more than once between two Wait(), or calling Wait() more than once between two Release(), will results in an undefined behavior.
///
/// Returns true if this operation succeeded.
bool Release();
@@ -514,7 +590,7 @@ Kernel Mode Objects
#endif
};
- /// Semaphore.
+ /// Semaphore. or is required to initialize a semaphore.
class Semaphore : public WaitableObject
{
private:
@@ -532,7 +608,7 @@ Kernel Mode Objects
/// Open an existing global named semaphore.
/// Returns true if this operation succeeded.
/// Set to true make the semaphore visible to all all child processes. This argument is only used in Windows.
- /// Name of the semaphore. This argument is ignored in Linux.
+ /// Name of the semaphore.
bool Open(bool inheritable, const WString& name);
/// Release the semaphore once.
@@ -547,7 +623,7 @@ Kernel Mode Objects
#endif
};
- /// Event.
+ /// Event. or is required to initialize an event.
class EventObject : public WaitableObject
{
private:
@@ -622,14 +698,20 @@ Thread Pool
Kernel Mode Objects in Process
***********************************************************************/
- ///
+ /// Critical section.
+ /// The macro "CS_LOCK" is recommended instead of calling [M:vl.CriticalSection.Enter] and [M:vl.CriticalSection.Leave] like this:
+ ///
+ /// // do something
/// }
- /// ]]>
+ /// ]]>
+ ///
+ ///
+ /// In Windows, enter a owned critical section will not result in dead lock.
+ /// In Linux and macOS, it works like a mutex.
+ ///
class CriticalSection : public Object, public NotCopyable
{
private:
@@ -659,19 +741,23 @@ Kernel Mode Objects in Process
};
};
- ///
/// Reader writer lock.
- /// The macro "READER_LOCK" and "WRITER_LOCK" are encouraged to use instead of calling [M:vl.ReaderWriterLock.EnterReader], [M:vl.ReaderWriterLock.LeaveReader], [M:vl.ReaderWriterLock.EnterWriter] and [M:vl.ReaderWriterLock.LeaveWriter] like this:
+ /// The macro "READER_LOCK" and "WRITER_LOCK" are recommended instead of calling [M:vl.ReaderWriterLock.EnterReader], [M:vl.ReaderWriterLock.LeaveReader], [M:vl.ReaderWriterLock.EnterWriter] and [M:vl.ReaderWriterLock.LeaveWriter] like this:
+ ///
+ /// // do something
/// }
+ /// ]]>
/// or
+ ///
+ /// // do something
/// }
- /// ]]>
+ /// ]]>
+ ///
class ReaderWriterLock : public Object, public NotCopyable
{
private:
@@ -731,28 +817,33 @@ Kernel Mode Objects in Process
/// The critical section.
bool SleepWith(CriticalSection& cs);
#ifdef VCZH_MSVC
- /// Bind a conditional variable with a owned critical section and release it for a period of time. When the function returns, the condition variable is activated or it is time out, and the current thread owned the critical section again. This function is only available in Windows.
+ /// Bind a conditional variable with a owned critical section and release it for a period of time. When the function returns, the condition variable is activated or it is time out, and the current thread owned the critical section again.
/// Returns true if this operation succeeded.
/// The critical section.
/// Time in milliseconds.
+ /// This function is only available in Windows.
bool SleepWithForTime(CriticalSection& cs, vint ms);
- /// Bind a conditional variable with a owned reader lock and release it. When the function returns, the condition variable is activated, and the current thread owned the reader lock again. This function is only available in Windows.
+ /// Bind a conditional variable with a owned reader lock and release it. When the function returns, the condition variable is activated, and the current thread owned the reader lock again.
/// Returns true if this operation succeeded.
/// The reader lock.
+ /// This function is only available in Windows.
bool SleepWithReader(ReaderWriterLock& lock);
- /// Bind a conditional variable with a owned reader lock and release it for a period of time. When the function returns, the condition variable is activated or it is time out, and the current thread owned the reader lock again. This function is only available in Windows.
+ /// Bind a conditional variable with a owned reader lock and release it for a period of time. When the function returns, the condition variable is activated or it is time out, and the current thread owned the reader lock again.
/// Returns true if this operation succeeded.
/// The reader lock.
/// Time in milliseconds.
+ /// This function is only available in Windows.
bool SleepWithReaderForTime(ReaderWriterLock& lock, vint ms);
- /// Bind a conditional variable with a owned writer lock and release it. When the function returns, the condition variable is activated, and the current thread owned the writer lock again. This function is only available in Windows.
+ /// Bind a conditional variable with a owned writer lock and release it. When the function returns, the condition variable is activated, and the current thread owned the writer lock again.
/// Returns true if this operation succeeded.
/// The writer lock.
+ /// This function is only available in Windows.
bool SleepWithWriter(ReaderWriterLock& lock);
- /// Bind a conditional variable with a owned writer lock and release it for a period of time. When the function returns, the condition variable is activated or it is time out, and the current thread owned the writer lock again. This function is only available in Windows.
+ /// Bind a conditional variable with a owned writer lock and release it for a period of time. When the function returns, the condition variable is activated or it is time out, and the current thread owned the writer lock again.
/// Returns true if this operation succeeded.
/// The writer lock.
/// Time in milliseconds.
+ /// This function is only available in Windows.
bool SleepWithWriterForTime(ReaderWriterLock& lock, vint ms);
#endif
/// Wake one thread that pending on this condition variable.
@@ -767,14 +858,16 @@ User Mode Objects
typedef long LockedInt;
- ///
+ /// Spin lock. It is similar to mutex, but it does not occupy resource in the system.
+ /// The macro "SPIN_LOCK" is recommended instead of calling [M:vl.SpinLock.Enter] and [M:vl.SpinLock.Leave] like this:
+ ///
+ /// // do something
/// }
- /// ]]>
+ /// ]]>
+ ///
class SpinLock : public Object, public NotCopyable
{
protected:
@@ -810,12 +903,13 @@ User Mode Objects
/***********************************************************************
Thread Local Storage
-
-ThreadLocalStorage and ThreadVariable are designed to be used as global value types only.
-Dynamically create instances of them are undefined behavior.
***********************************************************************/
/// Thread local storage operations.
+ ///
+ /// This class is designed to define global variables.
+ /// Dynamically allocation will result in undefined behavior.
+ ///
class ThreadLocalStorage : public Object, private NotCopyable
{
typedef void(*Destructor)(void*);
@@ -838,12 +932,16 @@ Dynamically create instances of them are undefined behavior.
static void FixStorages();
/// Clear all storages for the current thread. For threads that are created using [T:vl.Thread], this function will be automatically called when before the thread exit.
static void ClearStorages();
- /// Clear all storages for the current thread (should be the main thread) and clear all records. This function can only be called by the main thread when all other threads are exited. It will reduce noices when you want to detect memory leaks.
+ /// Clear all storages for the current thread (should be the main thread) and clear all records. This function can only be called by the main thread when all other threads are exited. It will reduce noices for detecting memory leaks.
static void DisposeStorages();
};
- /// Thread local variable. This type can only be used to define global variables. Different threads can store different values to and obtain differnt values from a thread local variable.
+ /// Thread local variable. Different threads can store different values to and obtain differnt values from a thread local variable.
/// Type of the storage.
+ ///
+ /// This class is designed to define global variables.
+ /// Dynamically allocation will result in undefined behavior.
+ ///
template
class ThreadVariable : public Object, private NotCopyable
{
@@ -938,7 +1036,13 @@ Dynamically create instances of them are undefined behavior.
RepeatingTaskExecutor
***********************************************************************/
- /// Queued task executor. It is different from a thread pool by: 1) Task execution is single threaded, 2) If you queue a task, it will override the the unexecuted queued task.
+ ///
+ /// Queued task executor. It is different from a thread because:
+ ///
+ /// Task execution is single threaded.
+ /// If you queue a task, it will override all unexecuted queued tasks.
+ ///
+ ///
/// The type of the argument to run a task.
template
class RepeatingTaskExecutor : public Object
@@ -1004,8 +1108,14 @@ RepeatingTaskExecutor
executingEvent.Leave();
}
- /// Queue a task. If there is a queued task that has not been executied yet, those tasks will be canceled. Only one task can be queued at the same moment.
+ /// Queue a task.
/// The argument to run a task.
+ ///
+ ///
+ /// When there is a running task, queuing a new task will cancel all unexecuted queued tasks.
+ /// When there is no running task, queuing a task will execute this task immediately.
+ ///
+ ///
void SubmitTask(const T& input)
{
SPIN_LOCK(inputLock)
@@ -1029,12 +1139,8 @@ RepeatingTaskExecutor
.\STREAM\INTERFACES.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Stream::Interfaces
-
-Interfaces:
- IStream : Stream
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_STREAM_INTERFACES
@@ -1046,66 +1152,78 @@ namespace vl
namespace stream
{
///
- /// Interface for streams. Stream functions are grouped into 5 categories:
- /// 1) Feature testing functions.
- /// 2) Read functions, available only if [M:vl.stream.IStream.CanRead] returns true.
- /// 3) Peek functions, available only if [M:vl.stream.IStream.CanPeek] returns true.
- /// 4) Write functions, available only if [M:vl.stream.IStream.CanWrite] returns true.
- /// 5) Seek functions, available only if [M:vl.stream.IStream.CanSeek] returns true.
- /// 6) Size functions, available only if [M:vl.stream.IStream.IsLimited] returns true. But there are still some streams knows that the content is limited, but the size is unknown. In this case, [M:vl.stream.IStream.Size] will return -1.
+ ///
+ /// Interface for streams.
+ ///
+ ///
+ /// Please notice that, even if you get a stream object, if [M:vl.stream.IStream.IsAvailable] returns false, all other methods cannot be used.
+ ///
+ ///
+ /// Not all methods are available for all types of streams.
+ /// Feature testing functions must be called before calling other methods, if it is not sure that what kind of stream is being operated against:
+ ///
+ ///
+ ///
+ /// Readable : A stream is readable if [M:vl.stream.IStream.CanRead] returns true.
+ /// Peekable : A stream is peekable if [M:vl.stream.IStream.CanPeek] returns true.
+ /// Writable : A stream is writable if [M:vl.stream.IStream.CanWrite] returns true.
+ /// Seekable : A stream is readable if [M:vl.stream.IStream.CanSeek] returns true.
+ /// Finite : A stream is finite if [M:vl.stream.IStream.IsLimited] returns true.
+ ///
+ ///
///
class IStream : public virtual Interface
{
public:
- /// Test if the stream is readable.
- /// Returns true if the stream is readable.
+ /// Test if the stream is readable .
+ /// Returns true if the stream is readable .
virtual bool CanRead()const=0;
- /// Test if the stream is writable.
- /// Returns true if the stream is writable.
+ /// Test if the stream is writable .
+ /// Returns true if the stream is writable .
virtual bool CanWrite()const=0;
- /// Test if the stream is seekable.
- /// Returns true if the stream is seekable.
+ /// Test if the stream is seekable .
+ /// Returns true if the stream is seekable .
virtual bool CanSeek()const=0;
- /// Test if the stream is peekable.
- /// Returns true if the stream is peekable.
+ /// Test if the stream is peekable .
+ /// Returns true if the stream is peekable .
virtual bool CanPeek()const=0;
- /// Test if the content of the stream is limited. A writable stream can also be limited, it means that you can only write a limited content to the stream.
- /// Returns true if the content of the stream is limited.
+ /// Test if the content of the stream is finite . A writable stream can also be limited, it means that you can only write limited content to the stream.
+ /// Returns true if the content of the stream is finite .
virtual bool IsLimited()const=0;
- /// Test if the stream is available. For example, if you create a readable [T:vl.stream.FileStream] giving a wrong file name, it will be unavailable.
- /// Returns true if the stream is available.
+ /// Test if the stream is available . For example, if you create a readable [T:vl.stream.FileStream] giving a wrong file name, it will be unavailable.
+ /// Returns true if the stream is available .
virtual bool IsAvailable()const=0;
- /// Close the stream.
+ /// Close the stream, making the stream unavailable .
virtual void Close()=0;
/// Get the current position in the stream.
- /// The position in the stream. Returns -1 if the stream is not available.
+ /// The position in the stream. Returns -1 if the stream is unavailable .
virtual pos_t Position()const=0;
- /// Get the size of the content..
- /// The size of the content. Returns -1 if the size is unknown or the stream is not available.
+ /// Get the size of the content in this stream.
+ /// The size of the content in this stream. Returns -1 if the size is unsizable or unavailable .
virtual pos_t Size()const=0;
- /// Step forward or backward from the current position. Will throw exception if the stream is not seekable or not available.
- /// The length of the step.
+ /// Step forward or backward from the current position. It will crash if the stream is unseekable or unavailable .
+ /// The length to step forward if it is a positive number. The length to step backward if it is a negative number
virtual void Seek(pos_t _size)=0;
- /// Step fowward from the beginning. Will throw exception if the stream is not seekable or not available.
- /// The length of the step.
+ /// Step forward from the beginning. It will crash if the stream is unseekable or unavailable .
+ /// The length to step forward.
virtual void SeekFromBegin(pos_t _size)=0;
- /// Step backward from the end. Will throw exception if the stream is not seekable or not available.
- /// The length of the step.
+ /// Step backward from the end. It will crash if the stream is unseekable or unavailable .
+ /// The length to step backward.
virtual void SeekFromEnd(pos_t _size)=0;
- /// Read from the current position and step forward. Will throw exception if the stream is not readable or not available.
- /// Returns the actual size of the content that is read. Returns 0 indicates that the stream reaches the end if the stream is limited.
+ /// Read from the current position and step forward. It will crash if the stream is unreadable or unavailable .
+ /// Returns the actual size of the content that has read. Returns 0 if a stream has no more data to read.
/// A buffer to store the content.
/// The size of the content that is expected to read.
virtual vint Read(void* _buffer, vint _size)=0;
- /// Write to the current position and step forward. Will throw exception if the stream is not writable or not available.
- /// Returns the actual size of the content that is written. Returns 0 indicates that the stream reaches the end if the stream is limited.
+ /// Write to the current position and step forward. It will crash if the stream is unwritable or unavailable .
+ /// Returns the actual size of the content that has written. Returns 0 if a stream has not enough space to write.
/// A buffer storing the content to write.
/// The size of the content that is expected to write.
virtual vint Write(void* _buffer, vint _size)=0;
- /// Read from the current position but not step forward. Will throw exception if the stream is not peekable or not available.
- /// Returns the actual size of the content that is read. Returns 0 indicates that the stream reaches the end if the stream is limited.
+ /// Read from the current position without stepping forward. It will crash if the stream is unpeekable or unavailable .
+ /// Returns the actual size of the content that is read. Returns 0 if a stream has no more data to read.
/// A buffer to store the content.
- /// The size of the content that is expected to peek.
+ /// The size of the content that is expected to read.
virtual vint Peek(void* _buffer, vint _size)=0;
};
@@ -1113,15 +1231,22 @@ namespace vl
class IEncoder : public Interface
{
public:
- /// Set a target writable stream. The function will transform the content and write to this tream.
- /// The target writable stream.
+ /// Set a target writable stream to receive data. transforms the content and write to this tream.
+ /// The target writable stream.
virtual void Setup(IStream* _stream)=0;
- /// Stop the transformation, ensuring all written content is transformed to the target stream.
+ /// Stop the transformation, ensuring all content is written to the target stream.
virtual void Close()=0;
- /// Transform content and write to the target stream. This function may cache something to increase performance, so it cannot expect that all transformed content will be written to the target stream immediately.
- /// Returns the actual size of the content before transforming that is written. The content is treated as being written even it is cached and not actually write to the target stream.
- /// A buffer storing the content to write.
- /// The size of the content that is expected to write.
+ ///
+ /// Transform content and write to the target stream.
+ /// This function could use caching to improve performance.
+ /// Please do not expect that all transformed content will be written to the target stream immediately.
+ ///
+ ///
+ /// Returns the actual size of the content that has written before transforming.
+ /// A successful write operation may only cache the data without actually write anything to the target stream.
+ ///
+ /// A buffer storing the content to transform.
+ /// The expected size of the content in bytes in "_buffer" to use.
virtual vint Write(void* _buffer, vint _size)=0;
};
@@ -1129,15 +1254,18 @@ namespace vl
class IDecoder : public Interface
{
public:
- /// Set a target readable stream. The function will read from this tream and transform the content.
- /// The target readable stream.
+ ///
+ /// Set a target readable stream.
+ /// reads from this tream and transform the content.
+ ///
+ /// The target readable stream.
virtual void Setup(IStream* _stream)=0;
/// Stop the transformation.
virtual void Close()=0;
/// Read from the target stream and transform the content.
- /// Returns the actual size of the content after transforming that is read.
+ /// Returns the actual size of the content has read after transforming.
/// A buffer to store the content.
- /// The size of the content that is expected to read.
+ /// The expected size of the content in bytes in "_buffer" to receive.
virtual vint Read(void* _buffer, vint _size)=0;
};
}
@@ -1149,12 +1277,8 @@ namespace vl
.\STREAM\BROADCASTSTREAM.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Stream::BroadcastStream
-
-Interfaces:
- BroadcastStream : Stream that copy the written data to multiple streams
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_STREAM_BROADCASTSTREAM
@@ -1165,7 +1289,10 @@ namespace vl
{
namespace stream
{
- /// A writable stream that copy written content to multiple target streams.
+ /// A writable stream that copy the written content to multiple output streams.
+ ///
+ /// When writing happens, the boreadcast stream will only performance one write attempt to each output stream.
+ ///
class BroadcastStream : public Object, public virtual IStream
{
typedef collections::List StreamList;
@@ -1174,12 +1301,15 @@ namespace vl
pos_t position;
StreamList streams;
public:
- /// Create a strema.
+ /// Create a boradcast stream.
BroadcastStream();
~BroadcastStream();
- /// Get the list of target streams. You can add streams to this list, or remove streams from this list.
- /// The list of target streams.
+ ///
+ /// Get the list of output streams.
+ /// You can change this list to subscribe or unsubscribe.
+ ///
+ /// The list of output streams.
StreamList& Targets();
bool CanRead()const;
bool CanWrite()const;
@@ -1206,12 +1336,8 @@ namespace vl
.\STREAM\CACHESTREAM.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Stream::CacheStream
-
-Interfaces:
- CacheStream : Stream that provide a cache for reading and writing
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_STREAM_CACHESTREAM
@@ -1223,9 +1349,21 @@ namespace vl
namespace stream
{
///
- /// A cache stream. Features (readable, writable, seekable, peekable) are enabled according to the target stream.
- /// When you read from the cache strema, it will read a specified size of content from the target stream first and cache, reducing the numbers of operations on the target stream.
- /// When you write to the cache strema, it will save them to a buffer, and write to the target stream until the buffer reaches a specified size, reducing the numbers of operations on the target stream.
+ ///
+ /// A potentially readable , peekable , writable , seekable and finite stream that creates on another stream.
+ /// Each feature is available if the target stream has the same feature.
+ ///
+ ///
+ /// When you read from the cache strema,
+ /// it will read a specified size of content from the target stream at once and cache,
+ /// reducing the number of operations on the target stream.
+ ///
+ ///
+ /// When you write to the cache stream,
+ /// it will cache all the data to write,
+ /// and write to the target stream after the cache is full,
+ /// reducing the number of operations on the target stream.
+ ///
///
class CacheStream : public Object, public virtual IStream
{
@@ -1246,7 +1384,7 @@ namespace vl
vint InternalRead(void* _buffer, vint _size);
vint InternalWrite(void* _buffer, vint _size);
public:
- /// Create a cache stream using a target stream.
+ /// Create a cache stream from a target stream.
/// The target stream.
/// Size of the cache.
CacheStream(IStream& _target, vint _block=65536);
@@ -1277,11 +1415,8 @@ namespace vl
.\STREAM\COMPRESSIONSTREAM.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Stream::CharFormat
-
-Classes:
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_STREAM_COMPRESSIONSTREAM
@@ -1333,7 +1468,11 @@ Compression
~LzwBase();
};
- /// An encoder to compress using Lzw algorithm.
+ /// An encoder to compress data using the Lzw algorithm.
+ ///
+ /// You are not recommended to compress data more than 1 mega bytes at once using the encoder directly.
+ /// and is recommended.
+ ///
class LzwEncoder : public LzwBase, public IEncoder
{
protected:
@@ -1348,8 +1487,15 @@ Compression
public:
/// Create an encoder.
LzwEncoder();
- /// Create an encoder and tell it which byte will never appear in the data before compression.
- /// An array to tell the encoder which byte will never appear in the data before compression.
+ /// Create an encoder, specifying what bytes will never appear in the data to compress.
+ ///
+ /// A filter array
+ /// If existingBytes[x] == true, it means x will possibly appear.
+ /// If existingBytes[x] == false, it means x will never appear.
+ ///
+ ///
+ /// The behavior is undefined, if existingBytes[x] == false, but byte x is actually in the data to compress.
+ ///
LzwEncoder(bool (&existingBytes)[256]);
~LzwEncoder();
@@ -1358,7 +1504,11 @@ Compression
vint Write(void* _buffer, vint _size)override;
};
- /// An decoder to decompress using Lzw algorithm.
+ /// An decoder to decompress data using the Lzw algorithm.
+ ///
+ /// You are not recommended to compress data more than 1 mega bytes at once using the encoder directly.
+ /// and is recommended.
+ ///
class LzwDecoder :public LzwBase, public IDecoder
{
protected:
@@ -1378,10 +1528,17 @@ Compression
void PrepareOutputBuffer(vint size);
void ExpandCodeToOutputBuffer(lzw::Code* code);
public:
- /// Create an decoder.
+ /// Create a decoder.
LzwDecoder();
- /// Create an decoder and tell it which byte will never appear in the data before compression.
- /// An array to tell the encoder which byte will never appear in the data before compression.
+ /// Create an encoder, specifying what bytes will never appear in the decompressed data.
+ ///
+ /// A filter array
+ /// If existingBytes[x] == true, it means x will possibly appear.
+ /// If existingBytes[x] == false, it means x will never appear.
+ ///
+ ///
+ /// The array "existingBytes" should exactly match the one given to .
+ ///
LzwDecoder(bool (&existingBytes)[256]);
~LzwDecoder();
@@ -1394,8 +1551,80 @@ Compression
Helper Functions
***********************************************************************/
+ /// Copy data from a readable input stream to a writable output stream.
+ /// Data copied in bytes.
+ /// The readable input stream.
+ /// The writable output stream.
extern vint CopyStream(stream::IStream& inputStream, stream::IStream& outputStream);
+
+ /// Compress data from a readable input stream to a writable output stream.
+ /// Data copied in bytes.
+ /// The readable input stream.
+ /// The writable output stream.
+ ///
+ /// Data is compressed in multiple batches,
+ /// the is expected output stream to have data in multiple parts.
+ /// In each part, the first 4 bytes is the data before compression in bytes.
+ /// the rest is the compressed data.
+ ///
+ ///
extern void CompressStream(stream::IStream& inputStream, stream::IStream& outputStream);
+
+ /// Decompress data from a readable input stream (with compressed data) to a writable output stream (with uncompressed data).
+ /// Data copied in bytes.
+ /// The readable input stream.
+ /// The writable output stream.
+ ///
+ /// Data is compressed in multiple batches,
+ /// the is expected input stream to have data in multiple parts.
+ /// In each part, the first 4 bytes is the data before compression in bytes.
+ /// the rest is the compressed data.
+ ///
+ ///
extern void DecompressStream(stream::IStream& inputStream, stream::IStream& outputStream);
}
}
@@ -1406,12 +1635,8 @@ Helper Functions
.\STREAM\FILESTREAM.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Stream::FileStream
-
-Interfaces:
- FileStream : File stream
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_STREAM_FILESTREAM
@@ -1423,27 +1648,27 @@ namespace vl
{
namespace stream
{
- /// A file stream. It is readable when you use [F:vl.stream.FileStream.AccessRight.ReadOnly] or [F:vl.stream.FileStream.AccessRight.ReadWrite] to create the stream. It is writable when you use [F:vl.stream.FileStream.AccessRight.WriteOnly] or [F:vl.stream.FileStream.AccessRight.ReadWrite] to create the stream.
+ /// A file stream. If the given file name is not working, the stream could be unavailable .
class FileStream : public Object, public virtual IStream
{
public:
/// Access to the file.
enum AccessRight
{
- /// The file is opened to read.
+ /// The file is opened to read, making this stream readable , seekable and finite .
ReadOnly,
- /// The file is opened to write.
+ /// The file is opened to write, making this stream writable .
WriteOnly,
- /// The file is opened to both read and write.
+ /// The file is opened to both read and write, making this stream readable , seekable and writable .
ReadWrite
};
protected:
AccessRight accessRight;
FILE* file;
public:
- /// Create a stream.
- /// File to operate.
- /// Operations want to perform on the file.
+ /// Create a file stream from a given file name.
+ /// The file to operate.
+ /// Expected operations on the file.
FileStream(const WString& fileName, AccessRight _accessRight);
~FileStream();
@@ -1472,12 +1697,8 @@ namespace vl
.\STREAM\MEMORYSTREAM.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Stream::MemoryStream
-
-Interfaces:
- MemoryStream : Memory stream
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_STREAM_MEMORYSTREAM
@@ -1488,7 +1709,7 @@ namespace vl
{
namespace stream
{
- /// A readable, writable, seekable and peekable stream that stores everything in memory.
+ /// A readable , peekable , writable and seekable stream that creates on a buffer.
class MemoryStream : public Object, public virtual IStream
{
protected:
@@ -1500,8 +1721,12 @@ namespace vl
void PrepareSpace(vint totalSpace);
public:
- /// Create a stream.
- /// Size for each allocation. The stream will only allocate new memory of size "_block" when it reaches the end and has to extend.
+ /// Create a memory stream.
+ ///
+ /// Size for each allocation.
+ /// When the allocated buffer is not big enough for writing,
+ /// the buffer will be rebuilt with an extension of "_block" in bytes.
+ ///
MemoryStream(vint _block=65536);
~MemoryStream();
@@ -1531,18 +1756,8 @@ namespace vl
.\STREAM\ACCESSOR.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Stream::Accessor
-
-Classes:
- TextReader : Text reader base class
- TextWriter : Text writer base class
- StringReader : Text reader from a string
- StreamReader : Text reader from a stream
- StreamWriter : Text writer to a stream
- EncoderStream : Stream that takes an encoder to translate another stream
- DecoderStream : Stream that takes a decoder to translate another stream
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_STREAM_ACCESSOR
@@ -1558,7 +1773,7 @@ namespace vl
Text Related
***********************************************************************/
- /// Text reader. All line breaks are normalized to CRLF regardless the format in the source.
+ /// Text reader. All line breaks are normalized to CRLF regardless whatever in the input stream.
class TextReader : public Object, private NotCopyable
{
public:
@@ -1568,15 +1783,15 @@ Text Related
/// Read a single character.
/// The character.
virtual wchar_t ReadChar()=0;
- /// Read a string of a specified size.
- /// The string.
+ /// Read a string of a specified size in characters.
+ /// The read string. It could be shorter than the expected length if the reader reaches the end.
/// Expected length of the string to read.
virtual WString ReadString(vint length);
/// Read a string until a line breaks is reached.
- /// The string. It does not contain the line break.
+ /// The string without the line break. If the reader reaches the end, it returns an empty string.
virtual WString ReadLine();
/// Read everying remain.
- /// The string.
+ /// The read string.
virtual WString ReadToEnd();
};
@@ -1588,18 +1803,18 @@ Text Related
/// The character to write.
virtual void WriteChar(wchar_t c)=0;
/// Write a string.
- /// Buffer to the string to write.
- /// Size of the string in characters not including the zero terminator.
+ /// Buffer of the string to write.
+ /// Size of the string in characters, not including the zero terminator.
virtual void WriteString(const wchar_t* string, vint charCount);
/// Write a string.
- /// Buffer to the zero terminated string to write.
+ /// Buffer of the zero terminated string to write.
virtual void WriteString(const wchar_t* string);
/// Write a string.
/// The string to write.
virtual void WriteString(const WString& string);
/// Write a string with a CRLF.
/// Buffer to the string to write.
- /// Size of the string in characters not including the zero terminator.
+ /// Size of the string in characters, not including the zero terminator.
virtual void WriteLine(const wchar_t* string, vint charCount);
/// Write a string with a CRLF.
/// Buffer to the zero terminated string to write.
@@ -1632,7 +1847,24 @@ Text Related
WString ReadToEnd();
};
- /// Text reader from a stream.
+ ///
+ /// Text reader from a stream storing characters in wchar_t.
+ ///
+ ///
+ /// To specify the encoding in the input stream,
+ /// you are recommended to create a with a ,
+ /// like , , , or .
+ ///
+ ///
class StreamReader : public TextReader
{
protected:
@@ -1645,8 +1877,25 @@ Text Related
bool IsEnd();
wchar_t ReadChar();
};
-
- /// Text writer to a stream.
+
+ ///
+ /// Text reader from a stream storing characters in wchar_t.
+ ///
+ ///
+ /// To specify the encoding in the input stream,
+ /// you are recommended to create a with a ,
+ /// like , , , or .
+ ///
+ ///
class StreamWriter : public TextWriter
{
protected:
@@ -1665,7 +1914,7 @@ Text Related
Encoding Related
***********************************************************************/
- /// Encoder stream, a writable stream using an [T:vl.stream.IEncoder] to transform content.
+ /// Encoder stream, a writable and potentially finite stream using [T:vl.stream.IEncoder] to transform content.
class EncoderStream : public virtual IStream
{
protected:
@@ -1674,8 +1923,8 @@ Encoding Related
pos_t position;
public:
- /// Create a stream.
- /// The target stream to write.
+ /// Create en encoder stream.
+ /// The output stream to write.
/// The encoder to transform content.
EncoderStream(IStream& _stream, IEncoder& _encoder);
~EncoderStream();
@@ -1697,7 +1946,7 @@ Encoding Related
vint Peek(void* _buffer, vint _size);
};
- /// Decoder stream, a readable stream using an [T:vl.stream.IDecoder] to transform content.
+ /// Decoder stream, a readable and potentially finite stream using [T:vl.stream.IDecoder] to transform content.
class DecoderStream : public virtual IStream
{
protected:
@@ -1706,8 +1955,8 @@ Encoding Related
pos_t position;
public:
- /// Create a stream.
- /// The target stream to read.
+ /// Create a decoder stream.
+ /// The input stream to read.
/// The decoder to transform content.
DecoderStream(IStream& _stream, IDecoder& _decoder);
~DecoderStream();
@@ -1733,6 +1982,27 @@ Encoding Related
Helper Functions
***********************************************************************/
+ ///
+ /// Build a big string using .
+ ///
+ /// The type of the callback.
+ /// The built big string.
+ ///
+ /// The callback to receive a big string.
+ /// The argument is a reference to a .
+ /// After the callback is executed, everything written to the writer will be returned from "GenerateToStream".
+ ///
+ /// Size of the cache in bytes.
+ ///
template
WString GenerateToStream(const TCallback& callback, vint block = 65536)
{
@@ -1756,12 +2026,8 @@ Helper Functions
.\STREAM\MEMORYWRAPPERSTREAM.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Stream::MemoryWrapperStream
-
-Interfaces:
- MemoryWrapperStream : Memory stream which manipulate a given buffer
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_STREAM_MEMORYWRAPPERSTREAM
@@ -1772,7 +2038,7 @@ namespace vl
{
namespace stream
{
- /// A readable, writable, seekable and peekable stream that operates a buffer.
+ /// A readable , peekable , writable , seekable and finite stream that creates on a buffer.
class MemoryWrapperStream : public Object, public virtual IStream
{
protected:
@@ -1780,9 +2046,9 @@ namespace vl
vint size;
vint position;
public:
- /// Create a stream.
+ /// Create a memory wrapper stream.
/// The buffer to operate.
- /// Size of the buffer.
+ /// Size of the buffer in bytes.
MemoryWrapperStream(void* _buffer, vint _size);
~MemoryWrapperStream();
@@ -1811,23 +2077,8 @@ namespace vl
.\STREAM\CHARFORMAT.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Stream::CharFormat
-
-Classes:
- CharEncoder : Encoder to translate from wchar_t to some specified format
- CharDecoder : Decoder to transate from some specified format to wchar_t
- MbcsEncoder : Mbcs encoder (using the code page of the current locale)
- MbcsDecoder : Mbcs decoder (using the code page of the current locale)
- Utf16Encoder : UTF-16 encoder
- Utf16Decoder : UTF-16 decoder
- Utf16BEEncoder : UTF-16 encoder with big endian
- Utf16BEDecoder : UTF-16 decoder with big endian
- Utf8Encoder : UTF-8 encoder
- Utf8Decoder : UTF-8 decoder
- BomEncoder : Character encoder which writes a BOM before the text
- BomDecoder : Character decoder which reads a BOM from the data to know the encoding
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_STREAM_CHARFORMAT
@@ -1840,18 +2091,18 @@ namespace vl
{
/*
- How UCS-4 translate to UTF-8
- U-00000000 - U-0000007F: 0xxxxxxx
- U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
- U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
- U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
- U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
- U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ How UCS-4 translates to UTF-8
+ U-00000000 - U-0000007F: 0xxxxxxx
+ U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
+ U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
+ U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
BOM:
- FFFE =Unicode (vceUtf16)
- FEFF =Unicode Big Endian (vceUtf16_be)
- EFBBBF =UTF-8 (vceUtf8)
- other =MBCS(GBK) (vceMbcs)
+ FFFE =Unicode
+ FEFF =Unicode Big Endian
+ EFBBBF =UTF-8
+ other =MBCS(GBK)
*/
/***********************************************************************
@@ -1896,14 +2147,14 @@ Char Encoder and Decoder
Mbcs
***********************************************************************/
- /// Encoder to transform text in a local code page from wchar_t.
+ /// Encoder to write text in the local code page.
class MbcsEncoder : public CharEncoder
{
protected:
vint WriteString(wchar_t* _buffer, vint chars);
};
- /// Encoder to transform text in a local code page to wchar_t.
+ /// Decoder to read text in the local code page.
class MbcsDecoder : public CharDecoder
{
protected:
@@ -1914,14 +2165,14 @@ Mbcs
Utf-16
***********************************************************************/
- /// Encoder to transform UTF-16 text from wchar_t.
+ /// Encoder to write UTF-16 text.
class Utf16Encoder : public CharEncoder
{
protected:
vint WriteString(wchar_t* _buffer, vint chars);
};
- /// Decoder to transform UTF-16 text to wchar_t.
+ /// Decoder to read UTF-16 text.
class Utf16Decoder : public CharDecoder
{
protected:
@@ -1932,14 +2183,14 @@ Utf-16
Utf-16-be
***********************************************************************/
- /// Encoder to transform big endian UTF-16 text from wchar_t.
+ /// Encoder to write big endian UTF-16 to.
class Utf16BEEncoder : public CharEncoder
{
protected:
vint WriteString(wchar_t* _buffer, vint chars);
};
- /// Decoder to transform big endian UTF-16 text to wchar_t.
+ /// Decoder to read big endian UTF-16 text.
class Utf16BEDecoder : public CharDecoder
{
protected:
@@ -1950,14 +2201,14 @@ Utf-16-be
Utf-8
***********************************************************************/
- /// Encoder to transform UTF-8 text from wchar_t.
+ /// Encoder to write UTF-8 text.
class Utf8Encoder : public CharEncoder
{
protected:
vint WriteString(wchar_t* _buffer, vint chars);
};
- /// Decoder to transform UTF-8 text to wchar_t.
+ /// Decoder to read UTF-8 text.
class Utf8Decoder : public CharDecoder
{
protected:
@@ -1974,7 +2225,7 @@ Utf-8
Bom
***********************************************************************/
- /// Encoder to transform text from wchar_t. A BOM will be added at the beginning.
+ /// Encoder to write text in a specified encoding. A BOM will be added at the beginning.
class BomEncoder : public Object, public IEncoder
{
public:
@@ -1983,19 +2234,19 @@ Bom
{
/// Multi-bytes character string.
Mbcs,
- /// UTF-8.
+ /// UTF-8. EF, BB, BF will be written before writing any text.
Utf8,
- /// UTF-16.
+ /// UTF-16. FF FE will be written before writing any text.
Utf16,
- /// Big endian UTF-16.
+ /// Big endian UTF-16. FE FF, BF will be written before writing any text.
Utf16BE
};
protected:
Encoding encoding;
IEncoder* encoder;
public:
- /// Create an encoder.
- /// Specified encoding.
+ /// Create an encoder with a specified encoding.
+ /// The specified encoding.
BomEncoder(Encoding _encoding);
~BomEncoder();
@@ -2004,7 +2255,7 @@ Bom
vint Write(void* _buffer, vint _size);
};
- /// Decoder to transform text to wchar_t. This decoder depends on the BOM information at the beginning to decide the format of the input.
+ /// Decoder to read text. This decoder depends on BOM at the beginning to decide the format of the input.
class BomDecoder : public Object, public IDecoder
{
private:
@@ -2039,7 +2290,7 @@ Bom
IStream* stream;
public:
- /// Create an decoder.
+ /// Create an decoder, BOM will be consumed before reading any text.
BomDecoder();
~BomDecoder();
@@ -2521,10 +2772,8 @@ Serialization
.\FILESYSTEM.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Framework::FileSystem
-
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_FILESYSTEM
@@ -2535,7 +2784,7 @@ namespace vl
{
namespace filesystem
{
- /// A type representing a file path.
+ /// Absolute file path.
class FilePath : public Object
{
protected:
@@ -2547,12 +2796,19 @@ namespace vl
static WString ComponentsToPath(const collections::List& components);
public:
#if defined VCZH_MSVC
+ /// The delimiter character used in a file path
+ ///
+ /// In Windows, it is "\".
+ /// In Linux and macOS, it is "/".
+ /// But you can always use "/", it is also supported in Windows.
+ ///
static const wchar_t Delimiter = L'\\';
#elif defined VCZH_GCC
static const wchar_t Delimiter = L'/';
#endif
/// Create a root path.
+ /// returns different values for root path on different platforms. Do not rely on the value.
FilePath();
/// Create a file path.
/// Content of the file path. If it is a relative path, it will be converted to an absolute path.
@@ -2583,6 +2839,7 @@ namespace vl
bool IsFile()const;
/// Test if the file path is a folder.
/// Returns true if the file path is a folder.
+ /// In Windows, a drive is also considered a folder.
bool IsFolder()const;
/// Test if the file path is a the root of all file system objects.
/// Returns true if the file path is the root of all file system objects.
@@ -2597,23 +2854,23 @@ namespace vl
/// Get the content of the file path.
/// The content of the file path.
WString GetFullPath()const;
- /// Calculate the relative path using a referencing folder.
+ /// Calculate the relative path based on a specified referencing folder.
/// The relative path.
/// The referencing folder.
WString GetRelativePathFor(const FilePath& _filePath);
};
- /// Representing a file reference.
+ /// A file.
class File : public Object
{
private:
FilePath filePath;
public:
- /// Create an empty reference.
+ /// Create an empty reference. An empty reference does not refer to any file.
File();
- /// Create a reference to a specified file.
+ /// Create a reference to a specified file. The file is not required to exist.
/// The specified file.
File(const FilePath& _filePath);
~File();
@@ -2622,35 +2879,41 @@ namespace vl
/// The file path.
const FilePath& GetFilePath()const;
- /// Get the content of the file as text with encoding testing.
- /// Returns false if this operation succeeded.
- /// The content of the file.
- /// The encoding.
- /// True if there is BOM.
+ /// Get the content of a text file with encoding testing.
+ /// Returns true if this operation succeeded.
+ /// Returns the content of the file.
+ /// Returns the encoding of the file.
+ /// Returns true if there is a BOM in the file.
bool ReadAllTextWithEncodingTesting(WString& text, stream::BomEncoder::Encoding& encoding, bool& containsBom);
- /// Get the content of the file as text.
+ /// Get the content of a text file. If there is no BOM in the file, the encoding is assumed to be aligned to the current code page.
/// The content of the file.
WString ReadAllTextByBom()const;
- /// Get the content of the file as text.
- /// Returns false if this operation succeeded.
+ /// Get the content of a text file.
+ /// Returns true if this operation succeeded.
/// The content of the file.
bool ReadAllTextByBom(WString& text)const;
- /// Get the content of the file as text.
- /// Returns false if this operation succeeded.
- /// The content of the file.
+ /// Get the content of a text file by lines.
+ /// Returns true if this operation succeeded.
+ /// The content of the file by lines.
+ ///
+ /// Lines could be separated by either CRLF or LF.
+ /// A text file is not required to ends with CRLF.
+ /// If the last character of the file is LF,
+ /// the last line is the line before LF.
+ ///
bool ReadAllLinesByBom(collections::List& lines)const;
/// Write text to the file.
- /// Returns false if this operation succeeded.
+ /// Returns true if this operation succeeded.
/// The text to write.
- /// Set to true to add a corresponding BOM at the beginning of the file according to the encoding.
- /// The text encoding.
+ /// Set to true to add a corresponding BOM at the beginning of the file according to the encoding, the default value is true.
+ /// The text encoding, the default encoding is UTF-16.
bool WriteAllText(const WString& text, bool bom = true, stream::BomEncoder::Encoding encoding = stream::BomEncoder::Utf16);
/// Write text to the file.
- /// Returns false if this operation succeeded.
- /// The text to write.
- /// Set to true to add a corresponding BOM at the beginning of the file according to the encoding.
- /// The text encoding.
+ /// Returns true if this operation succeeded.
+ /// The text to write, with CRLF appended after all lines.
+ /// Set to true to add a corresponding BOM at the beginning of the file according to the encoding, the default value is true.
+ /// The text encoding, the default encoding is UTF-16.
bool WriteAllLines(collections::List& lines, bool bom = true, stream::BomEncoder::Encoding encoding = stream::BomEncoder::Utf16);
/// Test does the file exist or not.
@@ -2658,23 +2921,25 @@ namespace vl
bool Exists()const;
/// Delete the file.
/// Returns true if this operation succeeded.
+ /// This function could return before the file is actually deleted.
bool Delete()const;
- /// Rename the file in the same folder.
+ /// Rename the file.
/// Returns true if this operation succeeded.
/// The new file name.
bool Rename(const WString& newName)const;
};
- /// Representing a folder reference.
+ /// A folder.
+ /// In Windows, a drive is also considered a folder.
class Folder : public Object
{
private:
FilePath filePath;
public:
- /// Create a root reference.
+ /// Create a reference to the root folder.
Folder();
- /// Create a reference to a specified folder.
+ /// Create a reference to a specified folder. The folder is not required to exist.
/// The specified folder.
Folder(const FilePath& _filePath);
~Folder();
@@ -2685,6 +2950,7 @@ namespace vl
/// Get all folders in this folder.
/// Returns true if this operation succeeded.
/// All folders.
+ /// In Windows, drives are considered sub folders in the root folder.
bool GetFolders(collections::List& folders)const;
/// Get all files in this folder.
/// Returns true if this operation succeeded.
@@ -2696,13 +2962,19 @@ namespace vl
bool Exists()const;
/// Create the folder.
/// Returns true if this operation succeeded.
- /// Set to true to create all parent folders if necessary.
+ /// Set to true to create all levels of containing folders if they do not exist.
+ ///
+ /// This function could return before the folder is actually created.
+ /// If "recursively" is false, this function will only attempt to create the specified folder directly,
+ /// it fails if the containing folder does not exist.
+ ///
bool Create(bool recursively)const;
/// Delete the folder.
/// Returns true if this operation succeeded.
/// Set to true to delete everything in the folder.
+ /// This function could return before the folder is actually deleted.
bool Delete(bool recursively)const;
- /// Rename the folder in the same folder.
+ /// Rename the folder.
/// Returns true if this operation succeeded.
/// The new folder name.
bool Rename(const WString& newName)const;
@@ -2717,12 +2989,8 @@ namespace vl
.\STREAM\RECORDERSTREAM.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Stream::RecorderStream
-
-Interfaces:
- RecorderStream : A readable stream that will copy the data to another stream on the fly
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_STREAM_RECORDERSTREAM
@@ -2733,16 +3001,29 @@ namespace vl
{
namespace stream
{
- /// A readable stream that, read from an stream, and write everything that is read to another stream.
+ ///
+ /// A readable stream that, reads from one stream, and copy everything that is read to another stream.
+ /// The stream is unavailable if one of the input stream or the output stream is unavailable .
+ /// The stream is readable , and potentially finite .
+ ///
+ ///
+ /// When reading happens, the recorder stream will only performance one write attempt to the output stream.
+ ///
class RecorderStream : public Object, public virtual IStream
{
protected:
IStream* in;
IStream* out;
public:
- /// Create a stream.
- /// The stream to read.
- /// The stream to write what is read from "_in".
+ /// Create a recorder stream.
+ ///
+ /// The input stream.
+ /// This recorder stream is readable only when the input stream is readable
+ /// This recorder stream is finite only when the input stream is finite
+ ///
+ ///
+ /// The output stream.
+ ///
RecorderStream(IStream& _in, IStream& _out);
~RecorderStream();
diff --git a/Import/VlppParser.cpp b/Import/VlppParser.cpp
index 242c939c..e82b3d9d 100644
--- a/Import/VlppParser.cpp
+++ b/Import/VlppParser.cpp
@@ -7,6 +7,11 @@ DEVELOPER: Zihan Chen(vczh)
/***********************************************************************
.\PARSING.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -1082,6 +1087,11 @@ Type Loader
/***********************************************************************
.\PARSINGANALYZER.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -2449,6 +2459,11 @@ ValidateDefinition
/***********************************************************************
.\PARSINGAUTOMATON.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -2753,6 +2768,11 @@ Automaton
/***********************************************************************
.\PARSINGAUTOMATON_CLOSURE.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -2900,6 +2920,11 @@ RemoveEpsilonTransitions
/***********************************************************************
.\PARSINGAUTOMATON_EPDA.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -3080,6 +3105,11 @@ CreateEpsilonPDA
/***********************************************************************
.\PARSINGAUTOMATON_GENERATETABLE.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -3784,6 +3814,11 @@ GenerateTable
/***********************************************************************
.\PARSINGAUTOMATON_JPDA.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -4126,6 +4161,11 @@ MarkLeftRecursiveInJointPDA
/***********************************************************************
.\PARSINGAUTOMATON_MERGESTATES.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -4417,6 +4457,11 @@ MergeStates
/***********************************************************************
.\PARSINGAUTOMATON_NPDA.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -4491,6 +4536,11 @@ CreateNondeterministicPDAFromEpsilonPDA
/***********************************************************************
.\PARSINGDEFINITIONS.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -4989,6 +5039,11 @@ ParsingDefinitionWriter
/***********************************************************************
.\PARSINGDEFINITIONS_CREATEPARSERDEFINITION.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -5720,6 +5775,11 @@ Bootstrap
/***********************************************************************
.\PARSINGLOGGING.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -6779,6 +6839,11 @@ Logger (ParsingTreeNode)
/***********************************************************************
.\PARSINGSTATE.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
#if defined(VCZH_GCC) && defined(__clang__)
#pragma clang diagnostic push
@@ -7905,6 +7970,11 @@ ParsingTransitionCollector
/***********************************************************************
.\PARSINGTABLE.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -8452,6 +8522,11 @@ ParsingTable
/***********************************************************************
.\PARSINGTREE.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
#if defined(VCZH_GCC) && defined(__clang__)
#pragma clang diagnostic push
diff --git a/Import/VlppParser.h b/Import/VlppParser.h
index 4c15a249..df87e688 100644
--- a/Import/VlppParser.h
+++ b/Import/VlppParser.h
@@ -11,11 +11,8 @@ DEVELOPER: Zihan Chen(vczh)
.\PARSINGTREE.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Parsing::Parsing Tree
-
-Classes:
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_PARSING_PARSINGTREE
@@ -586,11 +583,8 @@ Logging
.\PARSINGDEFINITIONS.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Parsing::Definitions
-
-Classes:
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_PARSING_PARSINGDEFINITIONS
@@ -1093,11 +1087,8 @@ Bootstrap
.\PARSINGANALYZER.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Parsing::Analyzing
-
-Classes:
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_PARSING_PARSINGANALYZER
@@ -1271,11 +1262,8 @@ Semantic Analyzer
.\PARSINGTABLE.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Parsing::Table
-
-Classes:
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_PARSING_PARSINGTABLE
@@ -1861,11 +1849,8 @@ Helper Functions
.\PARSINGAUTOMATON.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Parsing::Automaton
-
-Classes:
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_PARSING_PARSINGAUTOMATON
@@ -2093,11 +2078,8 @@ Helper: Parsing Table Generating
.\PARSINGSTATE.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Parsing::State
-
-Classes:
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_PARSING_PARSINGSTATE
@@ -2420,11 +2402,8 @@ AST Generating
.\PARSING.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Parsing::Parser
-
-Classes:
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_PARSING_PARSING
diff --git a/Import/VlppReflection.cpp b/Import/VlppReflection.cpp
index 8fec73e7..025ca9de 100644
--- a/Import/VlppReflection.cpp
+++ b/Import/VlppReflection.cpp
@@ -7,6 +7,11 @@ DEVELOPER: Zihan Chen(vczh)
/***********************************************************************
.\GUITYPEDESCRIPTOR.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -1153,6 +1158,11 @@ Cpp Helper Functions
/***********************************************************************
.\GUITYPEDESCRIPTORBUILDER.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -2438,6 +2448,11 @@ Function Related
/***********************************************************************
.\GUITYPEDESCRIPTORPREDEFINED.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -2589,6 +2604,11 @@ IValueException
/***********************************************************************
.\GUITYPEDESCRIPTORREFLECTION.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
#include
#include
@@ -3443,6 +3463,11 @@ LoadPredefinedTypes
/***********************************************************************
.\GUITYPEDESCRIPTOR_LOG.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
diff --git a/Import/VlppReflection.h b/Import/VlppReflection.h
index 0d7cfdcb..e47a16d6 100644
--- a/Import/VlppReflection.h
+++ b/Import/VlppReflection.h
@@ -10,11 +10,8 @@ DEVELOPER: Zihan Chen(vczh)
.\GUITYPEDESCRIPTOR.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Framework::Reflection
-
-Interfaces:
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_GUITYPEDESCRIPTOR
@@ -62,7 +59,64 @@ Attribute
};
}
- /// Base class of all reflectable object. You can use pointer or smart pointer to DescriptableObject to define variables, but if you want to create a reflectable class, you should inherit from [T:vl.reflection.Description`1].
+ ///
+ ///
+ /// Base class of all reflectable value types (class).
+ /// If you want to create a reflectable class, you should inherit from [T:vl.reflection.Description`1].
+ ///
+ ///
+ /// Inheriting from [T:vl.reflection.Description`1] is necessary even if you turned on "VCZH_DEBUG_NO_REFLECTION" preprocessor definition.
+ /// In this case, some members will be removed from this class to reduce the object size.
+ ///
+ ///
+ /// Ptr<DescriptableObject> is recommended to replace Ptr<Object> for holding a reflectable object.
+ /// When a class T inherits from [T:vl.reflection.Description`1], including DescriptableObject itself,
+ /// Ptr<T> is safe to be created directly from a T* hold by another Ptr<T> .
+ /// This is not allowed for all classes that do not inherit from [T:vl.reflection.Description`1].
+ ///
+ ///
+ ///
+ ///
+ /// When a class in Workflow script inherits from a class in C++,
+ /// since it is not possible to actually create a class in runtime,
+ /// so the created object from this Workflow class is multiple DescriptableObject grouping together.
+ ///
+ ///
+ /// This is called aggregation .
+ ///
+ ///
+ /// In this case, is required to do pointer casting to a C++ class.
+ ///
+ ///
+ /// To allow a C++ class to be aggregated,
+ /// use [T:vl.reflection.AggregatableDescription`1] instead of [T:vl.reflection.Description`1],
+ /// and call in the destructor.
+ /// If A inherits B and they are all aggregatable, do it in both destructors.
+ ///
+ ///
+ ///
+ /// {
+ /// public:
+ /// WString data;
+ /// };
+ ///
+ /// int main()
+ /// {
+ /// auto myClass = MakePtr();
+ /// myClass->data = L"Hello, world!";
+ ///
+ /// Ptr obj = myClass;
+ /// Console::WriteLine(obj.Cast()->data);
+ ///
+ /// // usually you cannot do this directly
+ /// // because obj and myClass share the same reference counter, but myClass2 doesn't
+ /// // this will cause the destructor delete MyClass twice and crash
+ /// // but it is different when MyClass inherits from Description or AggregatableDescription
+ /// auto myClass2 = Ptr(dynamic_cast(obj.Obj()));
+ /// Console::WriteLine(myClass2->data);
+ /// }
+ /// ]]>
class DescriptableObject
{
template
@@ -93,15 +147,31 @@ Attribute
protected:
#ifndef VCZH_DEBUG_NO_REFLECTION
+ // Returns true if this object inherits other objects by aggregation.
bool IsAggregated();
+
+ // Returnd the number of aggregated base objects.
vint GetAggregationSize();
+
+ // Return the object that inherit this object.
DescriptableObject* GetAggregationRoot();
+
+ // Notice that an object inherit this object, it is called by SetAggregationParent
void SetAggregationRoot(DescriptableObject* value);
+
+ // Return the specified aggregated base object
DescriptableObject* GetAggregationParent(vint index);
+
+ // Set an aggregated base class
void SetAggregationParent(vint index, DescriptableObject* value);
+
+ // Set an aggregated base class
void SetAggregationParent(vint index, Ptr& value);
+
+ // Must be called in Workflow generated classes that inherit from aggregatable C++ classes.
void InitializeAggregation(vint size);
#endif
+ /// A function that must be called in destructors of all classes inheriting from [T:vl.reflection.AggregatableDescription`1].
void FinalizeAggregation();
#ifndef VCZH_DEBUG_NO_REFLECTION
@@ -131,16 +201,29 @@ Attribute
virtual ~DescriptableObject();
#ifndef VCZH_DEBUG_NO_REFLECTION
- /// Get the type descriptor that describe the real type of this object.
+ ///
+ /// Get the type descriptor that describe the real type of this object.
+ ///
/// The real type.
+ ///
+ /// Only available when VCZH_DEBUG_NO_REFLECTION is off .
+ ///
description::ITypeDescriptor* GetTypeDescriptor();
#endif
- /// Get an internal property of this object. This map is totally for customization.
+ ///
+ /// Get an internal property of this object.
+ /// Internal properties are totally for customization,
+ /// they do not affect the object in anyway.
+ ///
/// Value of the internal property of this object.
/// Name of the property.
Ptr GetInternalProperty(const WString& name);
- /// Set an internal property of this object. This map is totally for customization.
+ ///
+ /// Set an internal property of this object.
+ /// Internal properties are totally for customization,
+ /// they do not affect the object in anyway.
+ ///
/// Name of the property.
/// Value of the internal property of this object.
void SetInternalProperty(const WString& name, Ptr value);
@@ -150,14 +233,32 @@ Attribute
bool Dispose(bool forceDisposing);
#ifndef VCZH_DEBUG_NO_REFLECTION
- /// Get the aggregation root object.
+ ///
+ /// Get the aggregation root object, which is the object that inherits this object by aggregation.
+ ///
/// The aggregation root object. If this object is not aggregated, or it is the root object of others, than this function return itself.
+ ///
+ /// Only available when VCZH_DEBUG_NO_REFLECTION is off .
+ ///
DescriptableObject* SafeGetAggregationRoot();
#endif
- /// Cast the object to another type, considered aggregation.
- /// The object with the expected type in all aggregated objects.
+ /// Cast the object to another type, this is required when the object is involved in aggregation.
+ /// The object with the expected type in all involved aggregated objects. It will crash when multiple objects are found to be qualified.
/// The expected type to cast.
+ ///
+ ///
+ /// A workflow class could inherit from multiple aggregatable C++ classes.
+ ///
+ ///
+ /// In order to do pointer casting correctly,
+ /// this function allow you to cast from one aggregated C++ base object to another aggregated C++ base object,
+ /// even when these two objects are not involved in inheriting in C++.
+ ///
+ ///
+ /// When VCZH_DEBUG_NO_REFLECTION is on , it performs dynamic_cast.
+ ///
+ ///
template
T* SafeAggregationCast()
{
@@ -171,247 +272,360 @@ Attribute
}
};
- ///
+ ///
+ /// Inherit from this class when you want to create a reflectable class.
+ /// It should be used like this:
+ ///
/// {
- /// ...
+ /// ..
/// };
- ///
- /// If you want YourClass to be inheritable in scripts, instead of using Description, you should use AggregatableDescription, like this:
+ /// ]]>
+ ///
+ ///
+ /// If you want YourClass to be inheritable in scripts,
+ /// instead of using Description,
+ /// you should use , like this:
+ ///
/// {
- /// ~YourClass()
- /// {
- /// FinalizeAggregation();
- /// }
+ /// ~YourClass()
+ /// {
+ /// FinalizeAggregation();
+ /// }
/// };
+ /// ]]>
+ ///
+ ///
+ /// After you complete your type,
+ /// use the following macros and functions to register your class into the global type table.
+ ///
+ ///
+ /// Some of the predefined type has already been registered.
+ /// If your types depend on these types, you should load those types by calling some or all of them:
+ ///
+ /// [F:vl.reflection.description.LoadPredefinedTypes]
+ /// [F:vl.reflection.description.LoadParsingTypes]
+ /// [F:vl.reflection.description.JsonLoadTypes]
+ /// [F:vl.reflection.description.XmlLoadTypes]
+ ///
+ /// But if you link GacUIReflection.cpp in your project and set VCZH_DEBUG_NO_REFLECTION to off,
+ /// all types will be automatically loaded before GuiMain is called.
+ ///
+ ///
+ /// The order does not matter, because content of types are lazily loaded.
+ ///
+ ///
+ /// Everything below should be put in vl::reflection::description namespaces.
+ ///
+ ///
+ /// (in header files) Create a macro that contains all types that you want to register.
+ /// Content in the list will become full names for registered type,
+ /// so it is strongly recommended to use the full name.
+ ///
+ ///
+ ///
+ /// in header files) Connect type names and types:
+ ///
+ ///
+ ///
+ /// (in cpp files) Connect type names and types:
+ ///
+ ///
+ ///
+ /// (in cpp files) Register all members:
+ ///
+ ///
+ /// You will need to define a macro for commas, Whatever name is fine.
+ ///
+ ///
+ ///
+ /// enum :
+ /// use BEGIN_ENUM_ITEM_MERGABLE instead of BEGIN_ENUM_ITEM if enum items are flags instead of concrete items.
+ ///
+ ///
+ ///
+ /// enum class:
+ /// use BEGIN_ENUM_ITEM_MERGABLE instead of BEGIN_ENUM_ITEM if enum items are flags instead of concrete items.
+ ///
+ ///
+ ///
+ /// struct :
+ /// It doesn't necessary mean a struct in C++.
+ /// Structs in reflection and Workflow script mean value types that carry only data, without methods and inheritance.
+ ///
+ ///
+ ///
+ ///
+ /// class :
+ /// It doesn't necessary mean a class in C++.
+ /// Classes in reflection and Workflow script mean reference types.
+ ///
+ ///
+ /// Here are all macros that register content of classes
+ ///
+ /// CLASS_MEMBER_BASE
+ /// CLASS_MEMBER_FIELD
+ /// CLASS_MEMBER_CONSTRUCTOR
+ /// CLASS_MEMBER_EXTERNALCTOR(_TEMPLATE)?
+ /// CLASS_MEMBER_METHOD(_OVERLOAD)?_RENAME
+ /// CLASS_MEMBER_(STATIC_)?METHOD(_OVERLOAD)?
+ /// CLASS_MEMBER_(STATIC_)?EXTERNALMETHOD(_TEMPLATE)?
+ /// CLASS_MEMBER_PROPERTY(_EVENT)?(_READONLY)?(_FAST)?
+ /// CLASS_MEMBER_PROPERTY_REFERENCETEMPLATE
+ /// CLASS_MEMBER_EVENT
+ ///
+ ///
+ ///
+ /// (), NO_PARAMETER)
///
- /// 4) (in cpp files) Register all members:
- ///
- /// #define _ ,
+ /// // 05) Constructor with arguments.
+ /// CLASS_MEMBER_CONSTRUCTOR(Ptr(int, const WString&), {L"numberParameter" _ L"stringParameter"})
///
- /// a) enum:
- /// use BEGIN_ENUM_ITEM_MERGABLE instead of BEGIN_ENUM_ITEM if enum items are consider mergable using "|".
+ /// // 06) Inject a global function as a constructor.
+ /// CLASS_MEMBER_EXTERNALCTOR(Ptr(int, const WString&), {L"numberParameter" _ L"stringParameter"}, mynamespace::CreateMyClass)
///
- /// BEGIN_ENUM_ITEM(Season)
- /// ENUM_ITEM(Spring)
- /// ENUM_ITEM(Summer)
- /// ENUM_ITEM(Autumn)
- /// ENUM_ITEM(Winter)
- /// END_ENUM_ITEM(Season)
+ /// // 07) Inject a consturctor and specify how to generate C++ code, "*" means not able to generate.
+ /// CLASS_MEMBER_EXTERNALCTOR_TEMPLATE(Ptr(int, const WString&), {L"numberParameter" _ L"stringParameter"}, CreateMyClass, L"mynamespace::GetMyClass($Arguments)", L"::vl::Func<$Func>(&mynamespace::GetMyClass)")
+ /// CLASS_MEMBER_EXTERNALCTOR_TEMPLATE(Ptr(), NO_PARAMETER, []()->Ptr{return nullptr;}, L"*", L"*")
///
- /// b) enum class:
- /// use BEGIN_ENUM_ITEM_MERGABLE instead of BEGIN_ENUM_ITEM if enum items are consider mergable using "|".
+ /// // 08) Add unoverloaded functions.
+ /// CLASS_MEMBER_METHOD(MyFunction1, NO_PARAMETER)
+ /// CLASS_MEMBER_METHOD(MyFunction2, {L"parameter1" _ L"parameter2"})
///
- /// BEGIN_ENUM_ITEM(Season)
- /// ENUM_CLASS_ITEM(Spring)
- /// ENUM_CLASS_ITEM(Summer)
- /// ENUM_CLASS_ITEM(Autumn)
- /// ENUM_CLASS_ITEM(Winter)
- /// END_ENUM_ITEM(Season)
+ /// // 09) Add unoverloaded functions but give different names. Unoverloaded only means in C++, not in renamed functions.
+ /// CLASS_MEMBER_METHOD_RENAME(MyNewName1, MyFunction1, NO_PARAMETER)
+ /// CLASS_MEMBER_METHOD_RENAME(MyNewName2, MyFunction2, {L"parameter1" _ L"parameter2"})
///
- /// c) struct (pure data structure):
- /// BEGIN_STRUCT_MEMBER(Point)
- /// STRUCT_MEMBER(x)
- /// STRUCT_MEMBER(y)
- /// END_STRUCT_MEMBER(Point)
+ /// // 10) Add overloaded functions, with function type specified in method pointers
+ /// CLASS_MEMBER_METHOD_OVERLOAD(MyFunction3, NO_PARAMETER, int(MyClass::*)())
+ /// CLASS_MEMBER_METHOD_OVERLOAD(MyFunction3, {L"parameter"}, int(MyClass::*)(int))
+ /// CLASS_MEMBER_METHOD_OVERLOAD(MyFunction3, {L"parameter1" _ L"parameter2"}, int(MyClass::*)(int, const WString&))
///
- /// d) class:
- /// BEGIN_CLASS_MEMBER(MyClass)
+ /// // 11) Add overloaded functions but give different names.
+ /// CLASS_MEMBER_METHOD_OVERLOAD_RENAME(MyNewName3, MyFunction3, NO_PARAMETER, int(MyClass::*)())
+ /// CLASS_MEMBER_METHOD_OVERLOAD_RENAME(MyNewName4, MyFunction3, {L"parameter"}, int(MyClass::*)(int))
+ /// CLASS_MEMBER_METHOD_OVERLOAD_RENAME(MyNewName4, MyFunction3, {L"parameter1" _ L"parameter2"}, int(MyClass::*)(int, const WString&))
///
- /// I) declare a base class (can have multiple base classes):
- /// CLASS_MEMBER_BASE(MyBaseClass)
+ /// // 12) Inject global functions as methods:
+ /// CLASS_MEMBER_EXTERNALMETHOD(MyNewName5, {L"parameter"}, int(MyClass::*)(int), mynamespace::AGlobalFunction)
///
- /// II) declare a field:
- /// CLASS_MEMBER_FIELD(myField)
+ /// // 13) Inject a method and specify how to generate C++ code, "*" means not able to generate.
+ /// CLASS_MEMBER_EXTERNALMETHOD_TEMPLATE(MyNewName5, {L"parameter1" _ L"parameter2"}, int(MyClass::*)(int, const WString&), [](MyClass* a, int b, const WString& c){return 0;}, L"*", L"*")
///
- /// III) Empty constructor that results in a raw pointer:
- /// CLASS_MEMBER_CONSTRUCTIOR(MyClass*(), NO_PARAMETER)
+ /// // 14) Add unoverloaded static functions
+ /// CLASS_MEMBER_STATIC_METHOD(MyFunction4, NO_PARAMETER)
+ /// CLASS_MEMBER_STATIC_METHOD(MyFunction5, {L"parameter1" _ L"parameter2"})
///
- /// IV) Empty constructor that results in a smart pointer:
- /// CLASS_MEMBER_CONSTRUCTIOR(Ptr(), NO_PARAMETER)
+ /// // 15) Add overloaded static functions
+ /// CLASS_MEMBER_STATIC_METHOD_OVERLOAD(MyFunction6, NO_PARAMETER, int(*)())
+ /// CLASS_MEMBER_STATIC_METHOD_OVERLOAD(MyFunction6, {L"parameter"}, int(*)(int))
+ /// CLASS_MEMBER_STATIC_METHOD_OVERLOAD(MyFunction6, {L"parameter1" _ L"parameter2"}, int(*)(int, const WString&))
///
- /// V) Constructor with arguments:
- /// CLASS_MEMBER_CONSTRUCTOR(Ptr(int, const WString&), {L"numberParameter" _ L"stringParameter"})
+ /// // 16) Inject global functions as static methods:
+ /// CLASS_MEMBER_STATIC_EXTERNALMETHOD(MyNewName6, {L"parameter"}, int(*)(int), mynamespace::AGlobalFunction2)
///
- /// VI) Inject a global function as a constructor
- /// CLASS_MEMBER_EXTERNALCTOR(Ptr(int, const WString&), {L"numberParameter" _ L"stringParameter"}, mynamespace::CreateMyClass)
- /// CLASS_MEMBER_EXTERNALCTOR_TEMPLATE(Ptr(int, const WString&), {L"numberParameter" _ L"stringParameter"}, CreateMyClass, L"mynamespace::GetMyClass($Arguments)", L"::vl::Func<$Func>(&mynamespace::GetMyClass)")
- /// CLASS_MEMBER_EXTERNALCTOR_TEMPLATE(Ptr(), NO_PARAMETER, []()->Ptr{return nullptr;}, L"*", L"*")
+ /// // 17) Inject a static method and specify how to generate C++ code, "*" means not able to generate.
+ /// CLASS_MEMBER_STATIC_EXTERNALMETHOD_TEMPLATE(MyNewName6, {L"parameter1" _ L"parameter2"}, int(*)(int, const WString&), [](int b, const WString& c){return 0;}, L"*")
///
- /// VII) Add unoverloaded functions
- /// CLASS_MEMBER_METHOD(MyFunction1, NO_PARAMETER)
- /// CLASS_MEMBER_METHOD(MyFunction2, {L"parameter1" _ L"parameter2"})
+ /// // 18) Add a getter function as a property
+ /// CLASS_MEMBER_PROPERTY_READONLY_FAST(X)
+ /// // which is short for
+ /// CLASS_MEMBER_METHOD(GetX, NO_PARAMETER)
+ /// CLASS_MEMBER_PROPERTY_READONLY(X, GetX)
///
- /// VIII) Add unoverloaded function but give a different names
- /// CLASS_MEMBER_METHOD_RENAME(MyNewName1, MyFunction1, NO_PARAMETER)
- /// CLASS_MEMBER_METHOD_RENAME(MyNewName2, MyFunction2, {L"parameter1" _ L"parameter2"})
+ /// // 19) Add a pair of getter and setter functions as a property
+ /// CLASS_MEMBER_PROPERTY_FAST(X)
+ /// // which is short for
+ /// CLASS_MEMBER_METHOD(GetX, NO_PARAMETER)
+ /// CLASS_MEMBER_METHOD(SetX, {L"value"})
+ /// CLASS_MEMBER_PROPERTY(X, GetX, SetX)
///
- /// IX) Add overloaded functions
- /// CLASS_MEMBER_METHOD_OVERLOAD(MyFunction3, NO_PARAMETER, int(MyClass::*)())
- /// CLASS_MEMBER_METHOD_OVERLOAD(MyFunction3, {L"parameter"}, int(MyClass::*)(int))
- /// CLASS_MEMBER_METHOD_OVERLOAD(MyFunction3, {L"parameter1" _ L"parameter2"}, int(MyClass::*)(int, const WString&))
+ /// // 20) Add a getter function as a property with a property changed event
+ /// CLASS_MEMBER_EVENT(XChanged)
+ /// CLASS_MEMBER_PROPERTY_EVENT_READONLY_FAST(X, XChanged)
+ /// // which is short for
+ /// CLASS_MEMBER_EVENT(XChanged)
+ /// CLASS_MEMBER_METHOD(GetX, NO_PARAMETER)
+ /// CLASS_MEMBER_PROPERTY_EVENT_READONLY(X, GetX, XChanged)
///
- /// IX) Add overloaded functions but give different names
- /// CLASS_MEMBER_METHOD_OVERLOAD_RENAME(MyNewName3, MyFunction3, NO_PARAMETER, int(MyClass::*)())
- /// CLASS_MEMBER_METHOD_OVERLOAD_RENAME(MyNewName4, MyFunction3, {L"parameter"}, int(MyClass::*)(int))
- /// CLASS_MEMBER_METHOD_OVERLOAD_RENAME(MyNewName4, MyFunction3, {L"parameter1" _ L"parameter2"}, int(MyClass::*)(int, const WString&))
+ /// // 21) Add a pair of getter and setter functions as a property with a property changed event
+ /// CLASS_MEMBER_EVENT(XChanged)
+ /// CLASS_MEMBER_PROPERTY_EVENT_FAST(X, XChanged)
+ /// // which is short for
+ /// CLASS_MEMBER_EVENT(XChanged)
+ /// CLASS_MEMBER_METHOD(GetX, NO_PARAMETER)
+ /// CLASS_MEMBER_METHOD(SetX, {L"value"})
+ /// CLASS_MEMBER_PROPERTY_EVENT(X, GetX, SetX, XChanged)
///
- /// X) Inject global functions as methods:
- /// CLASS_MEMBER_EXTERNALMETHOD(MyNewName5, {L"parameter"}, int(MyClass::*)(int), mynamespace::AGlobalFunction)
- /// CLASS_MEMBER_EXTERNALMETHOD_TEMPLATE(MyNewName5, {L"parameter1" _ L"parameter2"}, int(MyClass::*)(int, const WString&), [](MyClass* a, int b, const WString& c){return 0;}, L"*", L"*")
+ /// END_CLASS_MEMBER(MyClass)
+ /// ]]>
+ ///
+ ///
+ /// If the code compiles, the class should look like this:
+ ///
+ /// {
+ /// public:
+ /// MyClass();
+ /// MyClass(int numberParameter, const WString& stringParameter);
///
- /// XI) Add unoverloaded static functions
- /// CLASS_MEMBER_STATIC_METHOD(MyFunction4, NO_PARAMETER)
- /// CLASS_MEMBER_STATIC_METHOD(MyFunction5, {L"parameter1" _ L"parameter2"})
+ /// int MyFunction1();
+ /// int MyFunction2(int parameter1, const WString& parameter2);
+ /// int MyFunction3();
+ /// int MyFunction3(int parameter);
+ /// int MyFunction3(int parameter1, const WString& parameter2);
///
- /// XII) Add overloaded static functions
- /// CLASS_MEMBER_METHOD_OVERLOAD(MyFunction6, NO_PARAMETER, int(*)())
- /// CLASS_MEMBER_METHOD_OVERLOAD(MyFunction6, {L"parameter"}, int(*)(int))
- /// CLASS_MEMBER_METHOD_OVERLOAD(MyFunction6, {L"parameter1" _ L"parameter2"}, int(*)(int, const WString&))
+ /// static int MyFunction4();
+ /// static int MyFunction5(int parameter1, const WString& parameter2);
+ /// static int MyFunction6();
+ /// static int MyFunction6(int parameter);
+ /// static int MyFunction6(int parameter1, const WString& parameter2);
///
- /// XIII) Inject global functions as static methods:
- /// CLASS_MEMBER_STATIC_EXTERNALMETHOD(MyNewName6, {L"parameter"}, int(*)(int), mynamespace::AGlobalFunction2)
- /// CLASS_MEMBER_STATIC_EXTERNALMETHOD_INVOKETEMPLATE(MyNewName6, {L"parameter1" _ L"parameter2"}, int(*)(int, const WString&), [](int b, const WString& c){return 0;}, L"*")
+ /// Event XChanged;
+ /// int GetX();
+ /// void SetX(int value);
+ /// };
///
- /// XIV) Add a getter function as a property
- /// CLASS_MEMBER_PROPERTY_READONLY_FAST(X)
- /// which is short for
- /// CLASS_MEMBER_METHOD(GetX, NO_PARAMETER)
- /// CLASS_MEMBER_PROPERTY_READONLY(X, GetX)
+ /// Ptr CreateMyClass(int numberParameter, const WString7 stringParameter);
+ /// int GlobalFunction(MyClass* self, int parameter);
+ /// ]]>
+ ///
+ ///
+ ///
+ ///
+ /// interface :
+ /// A C++ class can be registered as a reflectable interface if:
+ ///
+ /// Directly or indirectly inherits [T:vl.reflection.IDescriptable]
+ /// The only registered constructor (if exists) should use Ptr<[T:vl.reflection.description.IValueInterfaceProxy]> as a parameter, so that a Workflow script class could implement this interface.
+ ///
+ ///
+ ///
+ /// Suppose you have an interface like this:
+ ///
+ /// {
+ /// public:
+ /// int GetX();
+ /// void SetX(int value);
+ /// };
+ /// ]]>
+ ///
+ ///
+ /// If you want to allow a Workflow script class implement this interface, you should first add a proxy like this:
+ ///
+ ///
+ ///
+ /// And then use this code to register the interface:
+ ///
+ ///
+ ///
+ /// Everything else is the same as registering classes.
+ /// Use BEGIN_INTERFACE_MEMBER_NOPROXY to register an interface without a proxy,
+ /// which means a Workflow script class cannot implement this interface.
+ ///
+ ///
+ ///
+ /// Undefine the macro for comma:
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// (in cpp files) Create a type loader:
+ ///
- /// {
- /// public:
- /// MyClass();
- /// MyClass(int numberParameter, const WString& stringParameter);
- ///
- /// int MyFunction1();
- /// int MyFunction2(int parameter1, const WString& parameter2);
- /// int MyFunction3();
- /// int MyFunction3(int parameter);
- /// int MyFunction3(int parameter1, const WString& parameter2);
- ///
- /// static int MyFunction4();
- /// static int MyFunction5(int parameter1, const WString& parameter2);
- /// static int MyFunction6();
- /// static int MyFunction6(int parameter);
- /// static int MyFunction6(int parameter1, const WString& parameter2);
- ///
- /// Event XChanged;
- /// int GetX();
- /// void SetX(int value);
- /// };
- ///
- /// Ptr CreateMyClass(int numberParameter, const WString7 stringParameter);
- /// int GlobalFunction(MyClass* self, int parameter);
- ///
- /// e) interface:
- /// An interface is defined by
- /// I) Directly or indirectly inherits [T:vl.reflection.IDescriptable]
- /// II) The only registered constructor (if exists) should use Ptr<[T:vl.reflection.description.IValueInterfaceProxy]> as a parameter
- ///
- /// Suppose you have an interface like this:
- /// class IMyInterface : public virtual IDescriptable, public Description
- /// {
- /// public:
- /// int GetX();
- /// void SetX(int value);
- /// };
- ///
- /// If you want this interface implementable by Workflow script, you should first add a proxy like this:
- /// #pragma warning(push)
- /// #pragma warning(disable:4250)
- /// BEGIN_INTERFACE_PROXY_NOPARENT_RAWPTR(IMyInterface)
- /// or BEGIN_INTERFACE_PROXY_RAWPTR(IMyInterface, baseInterfaces...)
- /// or BEGIN_INTERFACE_PROXY_NOPARENT_SHAREDPTR(IMyInterface)
- /// or BEGIN_INTERFACE_PROXY_SHAREDPTR(IMyInterface, baseInterfaces...)
- /// int GetX()override
- /// {
- /// INVOKEGET_INTERFACE_PROXY_NOPARAMS(GetX)
- /// }
- ///
- /// void SetX(int value)override
- /// {
- /// INVOKE_INTERFACE_PROXY(SetX, value)
- /// }
- /// END_INTERFACE_PROXY(IMyInterface)
- /// #pragma warning(pop)
- ///
- /// And then use this code to register the interface:
- /// BEGIN_INTERFACE_MEMBER(IMyInterface)
- /// ...
- /// END_INTERFACE_MEMBER(IMyInterface)
- ///
- /// Everything else is the same as registering classes. Use BEGIN_INTERFACE_MEMBER_NOPROXY to register an interface without a proxy, which means you cannot implement it in runtime dynamically.
- ///
- /// #undef _
- ///
- /// 5) (in cpp files) Create a type loader:
- /// class MyTypeLoader : public Object, public ITypeLoader
- /// {
- /// public:
- /// void Load(ITypeManager* manager)
- /// {
- /// MY_TYPELIST(ADD_TYPE_INFO)
- /// }
- ///
- /// void Unload(ITypeManager* manager)
- /// {
- /// }
- /// };
- ///
- /// 6) Load types when you think is a good timing using this code:
- /// vl::reflection::description::GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
- ///
- /// ]]>
- /// Type of your created reflection class.
+ /// void Unload(ITypeManager* manager)
+ /// {
+ /// }
+ /// };
+ /// ]]>
+ ///
+ ///
+ /// Before using reflection on registered types, you need to register the type loader:
+ /// AddTypeLoader(new MyTypeLoader);
+ /// ]]>
+ ///
+ ///
+ ///
+ ///
+ /// Type that inherit this class.
template
class Description : public virtual DescriptableObject
{
@@ -448,6 +662,10 @@ Attribute
#endif
};
+ ///
+ /// Inherit from this class when you want to create a reflectable class that can be inherited by Workflow script classes.
+ ///
+ /// Type that inherit this class.
template
class AggregatableDescription : public Description
{
@@ -458,7 +676,7 @@ Attribute
description::ITypeDescriptor* Description::associatedTypeDescriptor=0;
#endif
- /// Base types of all reflectable interfaces. All reflectable interface types should be virtual inherited.
+ /// Base type of all reflectable interfaces. All reflectable interface types should be virtual inherited.
class IDescriptable : public virtual Interface, public Description
{
public:
@@ -521,19 +739,28 @@ Value
};
/// A type to store all values of reflectable types.
+ ///
+ /// To convert between Value and its real C++ type, the following functions are recommended:
+ ///
+ /// [F:vl.reflection.description.BoxValue`1]
+ /// [F:vl.reflection.description.UnboxValue`1]
+ /// [F:vl.reflection.description.BoxParameter`1]
+ /// [F:vl.reflection.description.UnboxParameter`1]
+ ///
+ ///
class Value : public Object
{
public:
- /// Representing how the value is stored.
+ /// How the value is stored.
enum ValueType
{
/// The value is null.
Null,
- /// The value stored using a raw pointer.
+ /// The reference value is stored using a raw pointer.
RawPtr,
- /// The value stored using a smart pointer.
+ /// The reference value is stored using a shared pointer.
SharedPtr,
- /// The value stored using a boxed value.
+ /// The value is stored by boxing.
BoxedValue,
};
protected:
@@ -551,6 +778,7 @@ Value
vint Compare(const Value& a, const Value& b)const;
public:
+ /// Create a null value.
Value();
Value(const Value& value);
Value& operator=(const Value& value);
@@ -561,61 +789,1026 @@ Value
bool operator>(const Value& value)const { return Compare(*this, value)>0; }
bool operator>=(const Value& value)const { return Compare(*this, value) >= 0; }
- /// Get how the value is stored.
- /// How the value is stored.
+ /// Find out how the value is stored.
+ /// Returns How the value is stored.
ValueType GetValueType()const;
- /// Get the stored raw pointer if possible.
+ /// Get the stored raw pointer if GetValueType() returns RawPtr or SharedPtr .
/// The stored raw pointer. Returns null if failed.
DescriptableObject* GetRawPtr()const;
- /// Get the stored shared pointer if possible.
+ /// Get the stored shared pointer if GetValueType() returns SharedPtr .
/// The stored shared pointer. Returns null if failed.
Ptr GetSharedPtr()const;
- /// Get the stored text if possible.
+ /// Get the stored value if GetValueType() returns BoxedValue .
/// The stored text. Returns empty if failed.
Ptr GetBoxedValue()const;
- /// Get the real type of the stored object.
- /// The real type. Returns null if the value is null.
-
+ /// Test if this value isnull.
+ /// Returns true if this value is null.
bool IsNull()const;
#ifndef VCZH_DEBUG_NO_REFLECTION
+ /// Get the real type of the stored object.
+ /// The real type. Returns null if the value is null.
+ ///
+ /// Only available when VCZH_DEBUG_NO_REFLECTION is off .
+ ///
ITypeDescriptor* GetTypeDescriptor()const;
WString GetTypeFriendlyName()const;
bool CanConvertTo(ITypeDescriptor* targetType, ValueType targetValueType)const;
bool CanConvertTo(ITypeInfo* targetType)const;
#endif
- /// Store a raw pointer.
- /// The boxed value.
+ /// Create a value from a raw pointer.
+ /// The created value.
/// The raw pointer to store.
static Value From(DescriptableObject* value);
- /// Store a shared pointer.
- /// The boxed value.
+ /// Create a value from a shared pointer.
+ /// The created value.
/// The shared pointer to store.
static Value From(Ptr value);
- /// Store a text.
- /// The boxed value.
- /// The text to store.
- /// The type that you expect to interpret the text.
+ /// Create a boxed value.
+ /// The created value.
+ /// The boxed value to store.
+ /// The type of the boxed value.
static Value From(Ptr value, ITypeDescriptor* type);
#ifndef VCZH_DEBUG_NO_REFLECTION
static IMethodInfo* SelectMethod(IMethodGroupInfo* methodGroup, collections::Array& arguments);
+
+ /// Call the default constructor of the specified type to create a value.
+ /// The created value.
+ /// The type to create the value.
+ ///
+ /// Only available when VCZH_DEBUG_NO_REFLECTION is off .
+ ///
static Value Create(ITypeDescriptor* type);
+
+ /// Call the constructor of the specified type to create a value.
+ /// The created value.
+ /// The type to create the value.
+ /// Arguments for the constructor.
+ ///
+ /// Only available when VCZH_DEBUG_NO_REFLECTION is off .
+ ///
+ ///
+ /// {
+ /// public:
+ /// MyClass()
+ /// :data(L"Hello, world!")
+ /// {
+ /// }
+ ///
+ /// MyClass(const WString& _data)
+ /// :data(_data)
+ /// {
+ /// }
+ ///
+ /// WString data;
+ /// };
+ /// }
+ ///
+ /// #define MY_TYPELIST(F)\
+ /// F(mynamespace::MyClass)\
+ ///
+ /// // it is recommended to put the content below in a separated header file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// MY_TYPELIST(DECL_TYPE_INFO)
+ /// }
+ /// }
+ /// }
+ ///
+ /// // it is recommended to put the content below in a separated cpp file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// using namespace mynamespace;
+ ///
+ /// #define _ ,
+ ///
+ /// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
+ ///
+ /// BEGIN_CLASS_MEMBER(MyClass)
+ /// CLASS_MEMBER_CONSTRUCTOR(Ptr(), NO_PARAMETER)
+ /// CLASS_MEMBER_CONSTRUCTOR(Ptr(const WString&), { L"data" })
+ /// END_CLASS_MEMBER(MyClass)
+ ///
+ /// #undef _
+ /// }
+ /// }
+ /// }
+ ///
+ /// class MyTypeLoader : public Object, public ITypeLoader
+ /// {
+ /// public:
+ /// void Load(ITypeManager* manager)
+ /// {
+ /// MY_TYPELIST(ADD_TYPE_INFO)
+ /// }
+ ///
+ /// void Unload(ITypeManager* manager)
+ /// {
+ /// }
+ /// };
+ ///
+ /// // main function
+ ///
+ /// int main()
+ /// {
+ /// LoadPredefinedTypes();
+ /// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
+ /// GetGlobalTypeManager()->Load();
+ /// {
+ /// auto myClass = Value::Create(GetTypeDescriptor(L"mynamespace::MyClass"), (Value_xs(), WString(L"Hello, world!!!")));
+ ///
+ /// auto ptrMyClass1 = UnboxValue>(myClass);
+ /// Console::WriteLine(ptrMyClass1->data);
+ ///
+ /// Ptr ptrMyClass2;
+ /// UnboxParameter(myClass, ptrMyClass2);
+ /// Console::WriteLine(ptrMyClass2->data);
+ /// }
+ /// DestroyGlobalTypeManager();
+ /// }
+ /// ]]>
static Value Create(ITypeDescriptor* type, collections::Array& arguments);
+
+ /// Call the default constructor of the specified type to create a value.
+ /// The created value.
+ /// The registered full name for the type to create the value.
+ ///
+ /// Only available when VCZH_DEBUG_NO_REFLECTION is off .
+ ///
static Value Create(const WString& typeName);
+
+ /// Call the constructor of the specified type to create a value.
+ /// The created value.
+ /// The registered full name for the type to create the value.
+ /// Arguments for the constructor.
+ ///
+ /// Only available when VCZH_DEBUG_NO_REFLECTION is off .
+ ///
+ ///
+ /// {
+ /// public:
+ /// MyClass()
+ /// :data(L"Hello, world!")
+ /// {
+ /// }
+ ///
+ /// MyClass(const WString& _data)
+ /// :data(_data)
+ /// {
+ /// }
+ ///
+ /// WString data;
+ /// };
+ /// }
+ ///
+ /// #define MY_TYPELIST(F)\
+ /// F(mynamespace::MyClass)\
+ ///
+ /// // it is recommended to put the content below in a separated header file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// MY_TYPELIST(DECL_TYPE_INFO)
+ /// }
+ /// }
+ /// }
+ ///
+ /// // it is recommended to put the content below in a separated cpp file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// using namespace mynamespace;
+ ///
+ /// #define _ ,
+ ///
+ /// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
+ ///
+ /// BEGIN_CLASS_MEMBER(MyClass)
+ /// CLASS_MEMBER_CONSTRUCTOR(Ptr(), NO_PARAMETER)
+ /// CLASS_MEMBER_CONSTRUCTOR(Ptr(const WString&), { L"data" })
+ /// END_CLASS_MEMBER(MyClass)
+ ///
+ /// #undef _
+ /// }
+ /// }
+ /// }
+ ///
+ /// class MyTypeLoader : public Object, public ITypeLoader
+ /// {
+ /// public:
+ /// void Load(ITypeManager* manager)
+ /// {
+ /// MY_TYPELIST(ADD_TYPE_INFO)
+ /// }
+ ///
+ /// void Unload(ITypeManager* manager)
+ /// {
+ /// }
+ /// };
+ ///
+ /// // main function
+ ///
+ /// int main()
+ /// {
+ /// LoadPredefinedTypes();
+ /// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
+ /// GetGlobalTypeManager()->Load();
+ /// {
+ /// auto myClass = Value::Create(L"mynamespace::MyClass", (Value_xs(), WString(L"Hello, world!!!")));
+ ///
+ /// auto ptrMyClass1 = UnboxValue>(myClass);
+ /// Console::WriteLine(ptrMyClass1->data);
+ ///
+ /// Ptr ptrMyClass2;
+ /// UnboxParameter(myClass, ptrMyClass2);
+ /// Console::WriteLine(ptrMyClass2->data);
+ /// }
+ /// DestroyGlobalTypeManager();
+ /// }
+ /// ]]>
static Value Create(const WString& typeName, collections::Array& arguments);
+
+ /// Call a static method of the specified type.
+ /// The return value from that method.
+ /// The registered full name for the type.
+ /// The registered name for the method.
+ ///
+ /// Only available when VCZH_DEBUG_NO_REFLECTION is off .
+ ///
static Value InvokeStatic(const WString& typeName, const WString& name);
+
+ /// Call a static method of the specified type.
+ /// The return value from that method.
+ /// The registered full name for the type.
+ /// The registered name for the method.
+ /// Arguments for the method.
+ ///
+ /// Only available when VCZH_DEBUG_NO_REFLECTION is off .
+ ///
+ ///
+ /// {
+ /// public:
+ /// static void PrintHelloWorld(const WString& name)
+ /// {
+ /// Console::WriteLine(L"Hello, " + name + L"!");
+ /// }
+ /// };
+ /// }
+ ///
+ /// #define MY_TYPELIST(F)\
+ /// F(mynamespace::MyClass)\
+ ///
+ /// // it is recommended to put the content below in a separated header file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// MY_TYPELIST(DECL_TYPE_INFO)
+ /// }
+ /// }
+ /// }
+ ///
+ /// // it is recommended to put the content below in a separated cpp file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// using namespace mynamespace;
+ ///
+ /// #define _ ,
+ ///
+ /// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
+ ///
+ /// BEGIN_CLASS_MEMBER(MyClass)
+ /// CLASS_MEMBER_STATIC_METHOD(PrintHelloWorld, { L"name" })
+ /// END_CLASS_MEMBER(MyClass)
+ ///
+ /// #undef _
+ /// }
+ /// }
+ /// }
+ ///
+ /// class MyTypeLoader : public Object, public ITypeLoader
+ /// {
+ /// public:
+ /// void Load(ITypeManager* manager)
+ /// {
+ /// MY_TYPELIST(ADD_TYPE_INFO)
+ /// }
+ ///
+ /// void Unload(ITypeManager* manager)
+ /// {
+ /// }
+ /// };
+ ///
+ /// // main function
+ ///
+ /// int main()
+ /// {
+ /// LoadPredefinedTypes();
+ /// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
+ /// GetGlobalTypeManager()->Load();
+ /// {
+ /// Value::InvokeStatic(L"mynamespace::MyClass", L"PrintHelloWorld", (Value_xs(), WString(L"Gaclib")));
+ /// }
+ /// DestroyGlobalTypeManager();
+ /// }
+ /// ]]>
static Value InvokeStatic(const WString& typeName, const WString& name, collections::Array& arguments);
+
+ /// Call the getter function for a property.
+ /// The value of the property.
+ /// The registered name for the property.
+ ///
+ /// Only available when VCZH_DEBUG_NO_REFLECTION is off .
+ ///
+ ///
+ /// {
+ /// private:
+ /// WString prop;
+ /// public:
+ /// WString field;
+ ///
+ /// WString GetProp() { return prop; };
+ /// void SetProp(const WString& value) { prop = value; }
+ /// };
+ /// }
+ ///
+ /// #define MY_TYPELIST(F)\
+ /// F(mynamespace::MyClass)\
+ ///
+ /// // it is recommended to put the content below in a separated header file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// MY_TYPELIST(DECL_TYPE_INFO)
+ /// }
+ /// }
+ /// }
+ ///
+ /// // it is recommended to put the content below in a separated cpp file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// using namespace mynamespace;
+ ///
+ /// #define _ ,
+ ///
+ /// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
+ ///
+ /// BEGIN_CLASS_MEMBER(MyClass)
+ /// CLASS_MEMBER_CONSTRUCTOR(Ptr(), NO_PARAMETER)
+ /// CLASS_MEMBER_FIELD(field)
+ /// CLASS_MEMBER_PROPERTY_FAST(Prop)
+ /// END_CLASS_MEMBER(MyClass)
+ ///
+ /// #undef _
+ /// }
+ /// }
+ /// }
+ ///
+ /// class MyTypeLoader : public Object, public ITypeLoader
+ /// {
+ /// public:
+ /// void Load(ITypeManager* manager)
+ /// {
+ /// MY_TYPELIST(ADD_TYPE_INFO)
+ /// }
+ ///
+ /// void Unload(ITypeManager* manager)
+ /// {
+ /// }
+ /// };
+ ///
+ /// // main function
+ ///
+ /// int main()
+ /// {
+ /// LoadPredefinedTypes();
+ /// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
+ /// GetGlobalTypeManager()->Load();
+ /// {
+ /// auto td = GetTypeDescriptor(L"mynamespace::MyClass");
+ /// auto myClass = Value::Create(td);
+ ///
+ /// myClass.SetProperty(L"field", BoxValue(L"Hello, world!"));
+ /// myClass.SetProperty(L"Prop", BoxValue(L"Hello, Gaclib!"));
+ ///
+ /// Console::WriteLine(UnboxValue(myClass.GetProperty(L"field")));
+ /// Console::WriteLine(UnboxValue(myClass.GetProperty(L"Prop")));
+ /// }
+ /// DestroyGlobalTypeManager();
+ /// }
+ /// ]]>
Value GetProperty(const WString& name)const;
+
+ /// Call the setter function for a property.
+ /// The registered name for the property.
+ /// The value to set the property.
+ ///
+ /// Only available when VCZH_DEBUG_NO_REFLECTION is off .
+ ///
+ ///
+ /// {
+ /// private:
+ /// WString prop;
+ /// public:
+ /// WString field;
+ ///
+ /// WString GetProp() { return prop; };
+ /// void SetProp(const WString& value) { prop = value; }
+ /// };
+ /// }
+ ///
+ /// #define MY_TYPELIST(F)\
+ /// F(mynamespace::MyClass)\
+ ///
+ /// // it is recommended to put the content below in a separated header file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// MY_TYPELIST(DECL_TYPE_INFO)
+ /// }
+ /// }
+ /// }
+ ///
+ /// // it is recommended to put the content below in a separated cpp file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// using namespace mynamespace;
+ ///
+ /// #define _ ,
+ ///
+ /// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
+ ///
+ /// BEGIN_CLASS_MEMBER(MyClass)
+ /// CLASS_MEMBER_CONSTRUCTOR(Ptr(), NO_PARAMETER)
+ /// CLASS_MEMBER_FIELD(field)
+ /// CLASS_MEMBER_PROPERTY_FAST(Prop)
+ /// END_CLASS_MEMBER(MyClass)
+ ///
+ /// #undef _
+ /// }
+ /// }
+ /// }
+ ///
+ /// class MyTypeLoader : public Object, public ITypeLoader
+ /// {
+ /// public:
+ /// void Load(ITypeManager* manager)
+ /// {
+ /// MY_TYPELIST(ADD_TYPE_INFO)
+ /// }
+ ///
+ /// void Unload(ITypeManager* manager)
+ /// {
+ /// }
+ /// };
+ ///
+ /// // main function
+ ///
+ /// int main()
+ /// {
+ /// LoadPredefinedTypes();
+ /// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
+ /// GetGlobalTypeManager()->Load();
+ /// {
+ /// auto td = GetTypeDescriptor(L"mynamespace::MyClass");
+ /// auto myClass = Value::Create(td);
+ ///
+ /// myClass.SetProperty(L"field", BoxValue(L"Hello, world!"));
+ /// myClass.SetProperty(L"Prop", BoxValue(L"Hello, Gaclib!"));
+ ///
+ /// Console::WriteLine(UnboxValue(myClass.GetProperty(L"field")));
+ /// Console::WriteLine(UnboxValue(myClass.GetProperty(L"Prop")));
+ /// }
+ /// DestroyGlobalTypeManager();
+ /// }
+ /// ]]>
void SetProperty(const WString& name, const Value& newValue);
+
+ /// Call a non-static method.
+ /// The return value from that method.
+ /// The registered name for the method.
+ ///
+ /// Only available when VCZH_DEBUG_NO_REFLECTION is off .
+ ///
Value Invoke(const WString& name)const;
+
+ /// Call a non-static method.
+ /// The return value from that method.
+ /// The registered name for the method.
+ /// Arguments for the method.
+ ///
+ /// Only available when VCZH_DEBUG_NO_REFLECTION is off .
+ ///
+ ///
+ /// {
+ /// public:
+ /// void PrintHelloWorld(const WString& name)
+ /// {
+ /// Console::WriteLine(L"Hello, " + name + L"!");
+ /// }
+ /// };
+ /// }
+ ///
+ /// #define MY_TYPELIST(F)\
+ /// F(mynamespace::MyClass)\
+ ///
+ /// // it is recommended to put the content below in a separated header file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// MY_TYPELIST(DECL_TYPE_INFO)
+ /// }
+ /// }
+ /// }
+ ///
+ /// // it is recommended to put the content below in a separated cpp file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// using namespace mynamespace;
+ ///
+ /// #define _ ,
+ ///
+ /// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
+ ///
+ /// BEGIN_CLASS_MEMBER(MyClass)
+ /// CLASS_MEMBER_CONSTRUCTOR(Ptr(), NO_PARAMETER)
+ /// CLASS_MEMBER_METHOD(PrintHelloWorld, { L"name" })
+ /// END_CLASS_MEMBER(MyClass)
+ ///
+ /// #undef _
+ /// }
+ /// }
+ /// }
+ ///
+ /// class MyTypeLoader : public Object, public ITypeLoader
+ /// {
+ /// public:
+ /// void Load(ITypeManager* manager)
+ /// {
+ /// MY_TYPELIST(ADD_TYPE_INFO)
+ /// }
+ ///
+ /// void Unload(ITypeManager* manager)
+ /// {
+ /// }
+ /// };
+ ///
+ /// // main function
+ ///
+ /// int main()
+ /// {
+ /// LoadPredefinedTypes();
+ /// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
+ /// GetGlobalTypeManager()->Load();
+ /// {
+ /// auto td = GetTypeDescriptor(L"mynamespace::MyClass");
+ /// auto myClass = Value::Create(td);
+ /// myClass.Invoke(L"PrintHelloWorld", (Value_xs(), WString(L"Gaclib")));
+ /// }
+ /// DestroyGlobalTypeManager();
+ /// }
+ /// ]]>
Value Invoke(const WString& name, collections::Array& arguments)const;
+
+ /// Attach a callback function for the event.
+ /// The event handler for this attachment. You need to keep it to detach the callback function.
+ /// The registered name for the event.
+ /// The callback function.
+ ///
+ /// Only available when VCZH_DEBUG_NO_REFLECTION is off .
+ ///
+ ///
+ /// {
+ /// private:
+ /// WString prop;
+ /// public:
+ /// Event PropChanged;
+ ///
+ /// WString GetProp()
+ /// {
+ /// return prop;
+ /// }
+ ///
+ /// void SetProp(const WString& value)
+ /// {
+ /// if (prop != value)
+ /// {
+ /// auto old = prop;
+ /// prop = value;
+ /// PropChanged(old, prop);
+ /// }
+ /// }
+ /// };
+ /// }
+ ///
+ /// #define MY_TYPELIST(F)\
+ /// F(mynamespace::MyClass)\
+ ///
+ /// // it is recommended to put the content below in a separated header file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// MY_TYPELIST(DECL_TYPE_INFO)
+ /// }
+ /// }
+ /// }
+ ///
+ /// // it is recommended to put the content below in a separated cpp file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// using namespace mynamespace;
+ ///
+ /// #define _ ,
+ ///
+ /// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
+ ///
+ /// BEGIN_CLASS_MEMBER(MyClass)
+ /// CLASS_MEMBER_CONSTRUCTOR(Ptr(), NO_PARAMETER)
+ /// CLASS_MEMBER_EVENT(PropChanged)
+ /// CLASS_MEMBER_PROPERTY_EVENT_FAST(Prop, PropChanged)
+ /// END_CLASS_MEMBER(MyClass)
+ ///
+ /// #undef _
+ /// }
+ /// }
+ /// }
+ ///
+ /// class MyTypeLoader : public Object, public ITypeLoader
+ /// {
+ /// public:
+ /// void Load(ITypeManager* manager)
+ /// {
+ /// MY_TYPELIST(ADD_TYPE_INFO)
+ /// }
+ ///
+ /// void Unload(ITypeManager* manager)
+ /// {
+ /// }
+ /// };
+ ///
+ /// // main function
+ ///
+ /// int main()
+ /// {
+ /// LoadPredefinedTypes();
+ /// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
+ /// GetGlobalTypeManager()->Load();
+ /// {
+ /// auto td = GetTypeDescriptor(L"mynamespace::MyClass");
+ /// auto myClass = Value::Create(td);
+ /// myClass.SetProperty(L"Prop", BoxValue(L"Zero"));
+ ///
+ /// using CallbackType = Func;
+ /// CallbackType callbackFunction = [](const WString& oldProp, const WString& newProp)
+ /// {
+ /// Console::WriteLine(L"myClass.Prop changed: " + oldProp + L" -> " + newProp);
+ /// };
+ /// auto handler = myClass.AttachEvent(L"PropChanged", BoxParameter(callbackFunction));
+ ///
+ /// myClass.SetProperty(L"Prop", BoxValue(L"One"));
+ /// myClass.SetProperty(L"Prop", BoxValue(L"Two"));
+ /// myClass.DetachEvent(L"PropChanged", handler);
+ /// myClass.SetProperty(L"Prop", BoxValue(L"Three"));
+ /// }
+ /// DestroyGlobalTypeManager();
+ /// }
+ /// ]]>
Ptr AttachEvent(const WString& name, const Value& function)const;
+
+ /// Detach a callback function from the event.
+ /// Returns true if this operation succeeded.
+ /// The registered name for the event.
+ /// The event handler returned from .
+ ///
+ /// Only available when VCZH_DEBUG_NO_REFLECTION is off .
+ ///
+ ///
+ /// {
+ /// private:
+ /// WString prop;
+ /// public:
+ /// Event PropChanged;
+ ///
+ /// WString GetProp()
+ /// {
+ /// return prop;
+ /// }
+ ///
+ /// void SetProp(const WString& value)
+ /// {
+ /// if (prop != value)
+ /// {
+ /// auto old = prop;
+ /// prop = value;
+ /// PropChanged(old, prop);
+ /// }
+ /// }
+ /// };
+ /// }
+ ///
+ /// #define MY_TYPELIST(F)\
+ /// F(mynamespace::MyClass)\
+ ///
+ /// // it is recommended to put the content below in a separated header file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// MY_TYPELIST(DECL_TYPE_INFO)
+ /// }
+ /// }
+ /// }
+ ///
+ /// // it is recommended to put the content below in a separated cpp file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// using namespace mynamespace;
+ ///
+ /// #define _ ,
+ ///
+ /// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
+ ///
+ /// BEGIN_CLASS_MEMBER(MyClass)
+ /// CLASS_MEMBER_CONSTRUCTOR(Ptr(), NO_PARAMETER)
+ /// CLASS_MEMBER_EVENT(PropChanged)
+ /// CLASS_MEMBER_PROPERTY_EVENT_FAST(Prop, PropChanged)
+ /// END_CLASS_MEMBER(MyClass)
+ ///
+ /// #undef _
+ /// }
+ /// }
+ /// }
+ ///
+ /// class MyTypeLoader : public Object, public ITypeLoader
+ /// {
+ /// public:
+ /// void Load(ITypeManager* manager)
+ /// {
+ /// MY_TYPELIST(ADD_TYPE_INFO)
+ /// }
+ ///
+ /// void Unload(ITypeManager* manager)
+ /// {
+ /// }
+ /// };
+ ///
+ /// // main function
+ ///
+ /// int main()
+ /// {
+ /// LoadPredefinedTypes();
+ /// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
+ /// GetGlobalTypeManager()->Load();
+ /// {
+ /// auto td = GetTypeDescriptor(L"mynamespace::MyClass");
+ /// auto myClass = Value::Create(td);
+ /// myClass.SetProperty(L"Prop", BoxValue(L"Zero"));
+ ///
+ /// using CallbackType = Func;
+ /// CallbackType callbackFunction = [](const WString& oldProp, const WString& newProp)
+ /// {
+ /// Console::WriteLine(L"myClass.Prop changed: " + oldProp + L" -> " + newProp);
+ /// };
+ /// auto handler = myClass.AttachEvent(L"PropChanged", BoxParameter(callbackFunction));
+ ///
+ /// myClass.SetProperty(L"Prop", BoxValue(L"One"));
+ /// myClass.SetProperty(L"Prop", BoxValue(L"Two"));
+ /// myClass.DetachEvent(L"PropChanged", handler);
+ /// myClass.SetProperty(L"Prop", BoxValue(L"Three"));
+ /// }
+ /// DestroyGlobalTypeManager();
+ /// }
+ /// ]]>
bool DetachEvent(const WString& name, Ptr handler)const;
#endif
- /// Dispose the object is it is stored as a raw pointer.
- /// Returns true if the object is disposed. Returns false if the object cannot be disposed. An exception will be thrown if the reference counter is not 0.
+ /// Dispose the object if GetValueType() returns RawPtr .
+ ///
+ /// Returns true if the object is disposed.
+ /// Returns false if the object cannot be disposed.
+ /// An exception will be thrown if the reference counter is not 0.
+ ///
+ ///
+ /// {
+ /// public:
+ /// SharedClass()
+ /// {
+ /// Console::WriteLine(L"SharedClass::SharedClass()");
+ /// }
+ ///
+ /// ~SharedClass()
+ /// {
+ /// Console::WriteLine(L"SharedClass::~SharedClass()");
+ /// }
+ /// };
+ ///
+ /// class RawClass : public Object, public Description
+ /// {
+ /// public:
+ /// RawClass()
+ /// {
+ /// Console::WriteLine(L"RawClass::RawClass()");
+ /// }
+ ///
+ /// ~RawClass()
+ /// {
+ /// Console::WriteLine(L"RawClass::~RawClass()");
+ /// }
+ /// };
+ /// }
+ ///
+ /// #define MY_TYPELIST(F)\
+ /// F(mynamespace::SharedClass)\
+ /// F(mynamespace::RawClass)\
+ ///
+ /// // it is recommended to put the content below in a separated header file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// MY_TYPELIST(DECL_TYPE_INFO)
+ /// }
+ /// }
+ /// }
+ ///
+ /// // it is recommended to put the content below in a separated cpp file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// using namespace mynamespace;
+ ///
+ /// #define _ ,
+ ///
+ /// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
+ ///
+ /// BEGIN_CLASS_MEMBER(SharedClass)
+ /// CLASS_MEMBER_CONSTRUCTOR(Ptr(), NO_PARAMETER)
+ /// END_CLASS_MEMBER(SharedClass)
+ ///
+ /// BEGIN_CLASS_MEMBER(RawClass)
+ /// CLASS_MEMBER_CONSTRUCTOR(RawClass*(), NO_PARAMETER)
+ /// END_CLASS_MEMBER(RawClass)
+ ///
+ /// #undef _
+ /// }
+ /// }
+ /// }
+ ///
+ /// class MyTypeLoader : public Object, public ITypeLoader
+ /// {
+ /// public:
+ /// void Load(ITypeManager* manager)
+ /// {
+ /// MY_TYPELIST(ADD_TYPE_INFO)
+ /// }
+ ///
+ /// void Unload(ITypeManager* manager)
+ /// {
+ /// }
+ /// };
+ ///
+ /// // main function
+ ///
+ /// int main()
+ /// {
+ /// LoadPredefinedTypes();
+ /// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
+ /// GetGlobalTypeManager()->Load();
+ /// {
+ /// auto sharedClass = Value::Create(L"mynamespace::SharedClass");
+ /// auto rawClass = Value::Create(L"mynamespace::RawClass");
+ ///
+ /// Console::WriteLine(L"sharedClass is " + WString(sharedClass.GetValueType() == Value::SharedPtr ? L"SharedPtr" : L"RawPtr"));
+ /// Console::WriteLine(L"rawClass is " + WString(rawClass.GetValueType() == Value::SharedPtr ? L"SharedPtr" : L"RawPtr"));
+ ///
+ /// rawClass.DeleteRawPtr();
+ /// }
+ /// DestroyGlobalTypeManager();
+ /// }
+ /// ]]>
bool DeleteRawPtr();
};
@@ -949,6 +2142,7 @@ ITypeDescriptor
return (TypeDescriptorFlags)((vint)a | (vint)b);
}
+ /// Metadata class for reflectable types.
class ITypeDescriptor : public virtual IDescriptable, public Description
{
public:
@@ -1007,23 +2201,57 @@ ITypeManager
class ITypeManager;
+ /// Delay loading for registering reflectable types.
class ITypeLoader : public virtual Interface
{
public:
+ /// Called when it is time to register types.
+ /// The type manager.
virtual void Load(ITypeManager* manager)=0;
+
+ /// Called when it is time to unregister types.
+ /// The type manager.
+ ///
+ /// Types cannot be unregistered one by one,
+ /// they are removed at the same time by calling
+ /// [F:vl.reflection.description.DestroyGlobalTypeManager] or
+ /// [F:vl.reflection.description.ResetGlobalTypeManager].
+ /// Here is just a chance for reverse extra steps, when these steps are taken in .
+ ///
virtual void Unload(ITypeManager* manager)=0;
};
+ /// A type manager to access all reflectable types.
class ITypeManager : public virtual Interface
{
public:
+ /// Get the number of all registered types.
+ /// The number of all registered types.
virtual vint GetTypeDescriptorCount()=0;
+
+ /// Get one registered type.
+ /// A registered type specified by the index.
+ /// The index for retriving the registered type.
+ ///
+ /// The index itself does not has any specific meaning.
+ /// And it is no guarantee that an index will always return the same type for each execution of the same process.
+ ///
virtual ITypeDescriptor* GetTypeDescriptor(vint index)=0;
virtual ITypeDescriptor* GetTypeDescriptor(const WString& name)=0;
virtual bool SetTypeDescriptor(const WString& name, Ptr typeDescriptor)=0;
+ /// Delay register some types.
+ /// Returns true if this operation succeeded.
+ /// A type loader for delay registering.
+ ///
+ /// You can still call this function after is called.
+ /// In this case, there is no delay registering, all types in this loader will be registered immediately.
+ ///
virtual bool AddTypeLoader(Ptr typeLoader)=0;
virtual bool RemoveTypeLoader(Ptr typeLoader)=0;
+
+ /// Load all added type loaders.
+ /// Returns true if this operation succeeded.
virtual bool Load()=0;
virtual bool Unload()=0;
virtual bool Reload()=0;
@@ -1031,9 +2259,45 @@ ITypeManager
virtual ITypeDescriptor* GetRootType()=0;
};
+ /// Get the type manager.
+ /// Returns the type manager.
extern ITypeManager* GetGlobalTypeManager();
+
+ /// Unload all types and free the type manager.
+ /// Returns true if this operation succeeded.
+ ///
+ /// After calling this function, you can no longer register new types,
+ /// and calling will always get null.
+ ///
+
extern bool DestroyGlobalTypeManager();
+
+ /// Unload all types and reset the type manager.
+ /// Returns true if this operation succeeded.
+ ///
+ ///
+ /// This function is similar to ,
+ /// but calling this function allows types to be registsred again.
+ ///
+ ///
+ /// This function is very useful for unit testing.
+ /// In each test case, you can first register all types,
+ /// and after the test case is finished, call this function to reset all types.
+ /// You can do this again and again in the other test cases,
+ /// so that these test cases don't affect each other.
+ ///
+ ///
extern bool ResetGlobalTypeManager();
+
+ /// Get a registered type given the registered name.
+ /// Returns the metadata class for this registered type.
+ ///
+ /// The registered name.
+ /// Note that this is not the full name of the C++ type,
+ /// it is the name what is used to registere this type.
+ ///
+ /// Returning null means the type registration is declared but the type manager has not started.
+ ///
extern ITypeDescriptor* GetTypeDescriptor(const WString& name);
extern bool IsInterfaceType(ITypeDescriptor* typeDescriptor, bool& acceptProxy);
extern void LogTypeManager(stream::TextWriter& writer);
@@ -1191,11 +2455,8 @@ Exceptions
.\GUITYPEDESCRIPTORPREDEFINED.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Framework::Reflection
-
-Interfaces:
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_GUITYPEDESCRIPTORPREDEFINED
@@ -1215,75 +2476,675 @@ namespace vl
Collections
***********************************************************************/
+ /// The reflectable version of .
class IValueEnumerator : public virtual IDescriptable, public Description
{
public:
+ /// Get the reference to the current value in the enumerator.
+ /// The current value.
+ /// needs to be called to make the first value available.
virtual Value GetCurrent() = 0;
+
+ /// Get the position of the current value in the enumerator.
+ /// The position of the current value.
virtual vint GetIndex() = 0;
+
+ /// Prepare for the next value.
+ /// Returns false if there is no more value.
virtual bool Next() = 0;
};
+ /// The reflectable version of .
+ /// will create a storing a shared pointer to an instance of this interface from an enumerable.
+ ///
+ /// {
+ /// public:
+ /// MyClass(vint _data = 0)
+ /// :data(_data)
+ /// {
+ /// }
+ ///
+ /// vint data;
+ /// };
+ /// }
+ ///
+ /// #define MY_TYPELIST(F)\
+ /// F(mynamespace::MyClass)\
+ ///
+ /// // it is recommended to put the content below in a separated header file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// MY_TYPELIST(DECL_TYPE_INFO)
+ /// }
+ /// }
+ /// }
+ ///
+ /// // it is recommended to put the content below in a separated cpp file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// using namespace mynamespace;
+ ///
+ /// #define _ ,
+ ///
+ /// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
+ ///
+ /// BEGIN_CLASS_MEMBER(MyClass)
+ /// CLASS_MEMBER_CONSTRUCTOR(Ptr(), NO_PARAMETER)
+ /// CLASS_MEMBER_CONSTRUCTOR(Ptr(vint), { L"data" })
+ /// CLASS_MEMBER_FIELD(data)
+ /// END_CLASS_MEMBER(MyClass)
+ ///
+ /// #undef _
+ /// }
+ /// }
+ /// }
+ ///
+ /// class MyTypeLoader : public Object, public ITypeLoader
+ /// {
+ /// public:
+ /// void Load(ITypeManager* manager)
+ /// {
+ /// MY_TYPELIST(ADD_TYPE_INFO)
+ /// }
+ ///
+ /// void Unload(ITypeManager* manager)
+ /// {
+ /// }
+ /// };
+ ///
+ /// // main function
+ ///
+ /// int main()
+ /// {
+ /// LoadPredefinedTypes();
+ /// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
+ /// GetGlobalTypeManager()->Load();
+ /// {
+ /// LazyList> cs = Range(1, 10)
+ /// .Select([](vint i)
+ /// {
+ /// return MakePtr(i);
+ /// });
+ ///
+ /// Value boxed = BoxParameter>>(cs);
+ /// {
+ /// auto enumerable = UnboxValue>(boxed);
+ /// auto enumerator = enumerable->CreateEnumerator();
+ /// while (enumerator->Next())
+ /// {
+ /// Console::Write(itow(UnboxValue>(enumerator->GetCurrent())->data) + L" ");
+ /// }
+ /// Console::WriteLine(L"");
+ /// }
+ /// {
+ /// auto enumerator = boxed.Invoke(L"CreateEnumerator");
+ /// while (UnboxValue(enumerator.Invoke(L"Next")))
+ /// {
+ /// Console::Write(itow(UnboxValue(enumerator.GetProperty(L"Current").GetProperty(L"data"))) + L" ");
+ /// }
+ /// Console::WriteLine(L"");
+ /// }
+ /// }
+ /// DestroyGlobalTypeManager();
+ /// }
+ /// ]]>
class IValueEnumerable : public virtual IDescriptable, public Description
{
public:
+ ///
+ /// Create an enumerator. should be called before reading the first value.
+ ///
+ /// The enumerator.
virtual Ptr CreateEnumerator() = 0;
+ /// Create an enumerable from another lazy list.
+ /// The created enumerable.
+ /// The lazy list to wrap.
static Ptr Create(collections::LazyList values);
};
+ ///
+ /// The reflectable version of readonly
+ /// ,
+ /// or
+ ///
+ ///
class IValueReadonlyList : public virtual IValueEnumerable, public Description
{
public:
+ /// Get the number of elements in the container.
+ /// The number of elements.
virtual vint GetCount() = 0;
+
+ /// Get the reference to the specified element.
+ /// The reference to the specified element. It will crash when the index is out of range.
+ /// The index of the element.
virtual Value Get(vint index) = 0;
+
+ /// Test does the list contain a value or not.
+ /// Returns true if the list contains the specified value.
+ /// The value to test.
virtual bool Contains(const Value& value) = 0;
+
+ /// Get the position of a value in this list.
+ /// Returns the position of first element that equals to the specified value. Returns -1 if failed to find.
+ /// The value to find.
virtual vint IndexOf(const Value& value) = 0;
};
+ ///
+ /// The reflectable version of readonly
+ /// or
+ ///
+ ///
+ /// will create a storing a shared pointer to an instance of this interface from a container.
+ ///
+ /// {
+ /// public:
+ /// MyClass(vint _data = 0)
+ /// :data(_data)
+ /// {
+ /// }
+ ///
+ /// vint data;
+ /// };
+ /// }
+ ///
+ /// #define MY_TYPELIST(F)\
+ /// F(mynamespace::MyClass)\
+ ///
+ /// // it is recommended to put the content below in a separated header file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// MY_TYPELIST(DECL_TYPE_INFO)
+ /// }
+ /// }
+ /// }
+ ///
+ /// // it is recommended to put the content below in a separated cpp file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// using namespace mynamespace;
+ ///
+ /// #define _ ,
+ ///
+ /// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
+ ///
+ /// BEGIN_CLASS_MEMBER(MyClass)
+ /// CLASS_MEMBER_CONSTRUCTOR(Ptr(), NO_PARAMETER)
+ /// CLASS_MEMBER_CONSTRUCTOR(Ptr(vint), { L"data" })
+ /// CLASS_MEMBER_FIELD(data)
+ /// END_CLASS_MEMBER(MyClass)
+ ///
+ /// #undef _
+ /// }
+ /// }
+ /// }
+ ///
+ /// class MyTypeLoader : public Object, public ITypeLoader
+ /// {
+ /// public:
+ /// void Load(ITypeManager* manager)
+ /// {
+ /// MY_TYPELIST(ADD_TYPE_INFO)
+ /// }
+ ///
+ /// void Unload(ITypeManager* manager)
+ /// {
+ /// }
+ /// };
+ ///
+ /// // main function
+ ///
+ /// int main()
+ /// {
+ /// LoadPredefinedTypes();
+ /// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
+ /// GetGlobalTypeManager()->Load();
+ /// {
+ /// List> cs;
+ /// CopyFrom(cs, Range(1, 10)
+ /// .Select([](vint i)
+ /// {
+ /// return MakePtr(i);
+ /// })
+ /// );
+ ///
+ /// Value boxed = BoxParameter>>(cs);
+ /// {
+ /// auto list = UnboxValue>(boxed);
+ /// for (vint i = 0; i < list->GetCount(); i++)
+ /// {
+ /// Console::Write(itow(UnboxValue>(list->Get(i))->data) + L" ");
+ /// }
+ /// Console::WriteLine(L"");
+ /// }
+ ///
+ /// for (vint i = 1; i <= 5; i++)
+ /// {
+ /// cs.RemoveAt(i);
+ /// }
+ ///
+ /// {
+ /// for (vint i = 0; i < UnboxValue(boxed.GetProperty(L"Count")); i++)
+ /// {
+ /// Console::Write(itow(UnboxValue(boxed.Invoke(L"Get", (Value_xs(), i)).GetProperty(L"data"))) + L" ");
+ /// }
+ /// Console::WriteLine(L"");
+ /// }
+ /// }
+ /// DestroyGlobalTypeManager();
+ /// }
+ /// ]]>
class IValueList : public virtual IValueReadonlyList, public Description
{
public:
+ /// Replace an element in the specified position.
+ /// Returns true if this operation succeeded. It will crash when the index is out of range
+ /// The position of the element to replace.
+ /// The new value to replace.
virtual void Set(vint index, const Value& value) = 0;
+
+ /// Append a value at the end of the list.
+ /// The index of the added item.
+ /// The value to add.
virtual vint Add(const Value& value) = 0;
+
+ /// Insert a value at the specified position.
+ /// The index of the added item. It will crash if the index is out of range
+ /// The position to insert the value.
+ /// The value to add.
virtual vint Insert(vint index, const Value& value) = 0;
+
+ /// Remove an element from the list. If multiple elements equal to the specified value, only the first one will be removed.
+ /// Returns true if the element is removed.
+ /// The item to remove.
virtual bool Remove(const Value& value) = 0;
+
+ /// Remove an element at a specified position.
+ /// Returns true if the element is removed. It will crash when the index is out of range.
+ /// The index of the element to remove.
virtual bool RemoveAt(vint index) = 0;
+
+ /// Remove all elements.
virtual void Clear() = 0;
+ /// Create an empty list.
+ /// The created list.
static Ptr Create();
+
+ /// Create a list with elements copied from another readonly list.
+ /// The created list.
+ /// Elements to copy.
static Ptr Create(Ptr values);
+
+ /// Create a list with elements copied from another lazy list.
+ /// The created list.
+ /// Elements to copy.
static Ptr Create(collections::LazyList values);
};
+ ///
+ /// The reflectable version of list container which triggers an event whenever items are changed.
+ ///
+ ///
+ /// {
+ /// public:
+ /// MyClass(vint _data = 0)
+ /// :data(_data)
+ /// {
+ /// }
+ ///
+ /// vint data;
+ /// };
+ /// }
+ ///
+ /// #define MY_TYPELIST(F)\
+ /// F(mynamespace::MyClass)\
+ ///
+ /// // it is recommended to put the content below in a separated header file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// MY_TYPELIST(DECL_TYPE_INFO)
+ /// }
+ /// }
+ /// }
+ ///
+ /// // it is recommended to put the content below in a separated cpp file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// using namespace mynamespace;
+ ///
+ /// #define _ ,
+ ///
+ /// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
+ ///
+ /// BEGIN_CLASS_MEMBER(MyClass)
+ /// CLASS_MEMBER_CONSTRUCTOR(Ptr(), NO_PARAMETER)
+ /// CLASS_MEMBER_CONSTRUCTOR(Ptr(vint), { L"data" })
+ /// CLASS_MEMBER_FIELD(data)
+ /// END_CLASS_MEMBER(MyClass)
+ ///
+ /// #undef _
+ /// }
+ /// }
+ /// }
+ ///
+ /// class MyTypeLoader : public Object, public ITypeLoader
+ /// {
+ /// public:
+ /// void Load(ITypeManager* manager)
+ /// {
+ /// MY_TYPELIST(ADD_TYPE_INFO)
+ /// }
+ ///
+ /// void Unload(ITypeManager* manager)
+ /// {
+ /// }
+ /// };
+ ///
+ /// // main function
+ ///
+ /// int main()
+ /// {
+ /// LoadPredefinedTypes();
+ /// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
+ /// GetGlobalTypeManager()->Load();
+ /// {
+ /// ObservableList> cs;
+ /// CopyFrom(cs, Range(1, 10)
+ /// .Select([](vint i)
+ /// {
+ /// return MakePtr(i);
+ /// })
+ /// );
+ ///
+ /// Value boxed = BoxValue(cs.GetWrapper());
+ /// auto list = UnboxValue>(boxed);
+ /// {
+ /// for (vint i = 0; i < list->GetCount(); i++)
+ /// {
+ /// Console::Write(itow(UnboxValue>(list->Get(i))->data) + L" ");
+ /// }
+ /// Console::WriteLine(L"");
+ /// }
+ ///
+ /// {
+ /// using CallbackType = Func;
+ /// CallbackType callbackFunction = [](vint index, vint oldCount, vint newCount)
+ /// {
+ /// Console::WriteLine(L"ItemChanged(" + itow(index) + L", " + itow(oldCount) + L", " + itow(newCount) + L");");
+ /// };
+ ///
+ /// auto handler = boxed.AttachEvent(L"ItemChanged", BoxParameter(callbackFunction));
+ /// for (vint i = 1; i <= 5; i++)
+ /// {
+ /// cs.RemoveAt(i);
+ /// }
+ /// boxed.DetachEvent(L"ItemChanged", handler);
+ /// }
+ ///
+ /// {
+ /// for (vint i = 0; i < UnboxValue(boxed.GetProperty(L"Count")); i++)
+ /// {
+ /// Console::Write(itow(UnboxValue(boxed.Invoke(L"Get", (Value_xs(), i)).GetProperty(L"data"))) + L" ");
+ /// }
+ /// Console::WriteLine(L"");
+ /// }
+ /// }
+ /// DestroyGlobalTypeManager();
+ /// }
+ /// ]]>
class IValueObservableList : public virtual IValueList, public Description
{
typedef void ItemChangedProc(vint index, vint oldCount, vint newCount);
public:
+ ///
+ /// Event that is triggered whenever items are changed.
+ /// The first argument is the index of the first item that is changed.
+ /// The second argument is the number of original items that are replaced by new items.
+ /// The third argument is the number of new items that replace original items.
+ ///
+ ///
+ /// If an item is changed, oldCount and newCount are both 1.
+ /// If several items are removed from the list, newCount is 0.
+ /// If several items are inserted to the list, oldCount is 0.
+ /// This event is triggered when the updating is done, original items are not possible to access at the moment.
+ ///
Event ItemChanged;
+ /// Create an empty list.
+ /// The created list.
static Ptr Create();
+
+ /// Create a list with elements copied from another readonly list.
+ /// The created list.
+ /// Elements to copy.
static Ptr Create(Ptr values);
+
+ /// Create a list with elements copied from another lazy list.
+ /// The created list.
+ /// Elements to copy.
static Ptr Create(collections::LazyList values);
};
+ ///
+ /// The reflectable version of readonly .
+ ///
class IValueReadonlyDictionary : public virtual IDescriptable, public Description
{
public:
+ /// Get all keys.
+ /// All keys.
virtual Ptr GetKeys() = 0;
+
+ /// Get all values.
+ /// All values.
virtual Ptr GetValues() = 0;
+
+ /// Get the number of keys.
+ /// The number of keys. It is also the number of values.
virtual vint GetCount() = 0;
+
+ /// Get the value associated to a specified key.
+ /// The reference to the value. It will crash if the key does not exist.
+ /// The key to find.
virtual Value Get(const Value& key) = 0;
};
+ ///
+ /// The reflectable version of .
+ ///
+ /// will create a storing a shared pointer to an instance of this interface from a dictionary.
+ ///
+ /// {
+ /// public:
+ /// MyClass(vint _data = 0)
+ /// :data(_data)
+ /// {
+ /// }
+ ///
+ /// vint data;
+ /// };
+ /// }
+ ///
+ /// #define MY_TYPELIST(F)\
+ /// F(mynamespace::MyClass)\
+ ///
+ /// // it is recommended to put the content below in a separated header file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// MY_TYPELIST(DECL_TYPE_INFO)
+ /// }
+ /// }
+ /// }
+ ///
+ /// // it is recommended to put the content below in a separated cpp file
+ ///
+ /// namespace vl
+ /// {
+ /// namespace reflection
+ /// {
+ /// namespace description
+ /// {
+ /// using namespace mynamespace;
+ ///
+ /// #define _ ,
+ ///
+ /// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
+ ///
+ /// BEGIN_CLASS_MEMBER(MyClass)
+ /// CLASS_MEMBER_CONSTRUCTOR(Ptr(), NO_PARAMETER)
+ /// CLASS_MEMBER_CONSTRUCTOR(Ptr(vint), { L"data" })
+ /// CLASS_MEMBER_FIELD(data)
+ /// END_CLASS_MEMBER(MyClass)
+ ///
+ /// #undef _
+ /// }
+ /// }
+ /// }
+ ///
+ /// class MyTypeLoader : public Object, public ITypeLoader
+ /// {
+ /// public:
+ /// void Load(ITypeManager* manager)
+ /// {
+ /// MY_TYPELIST(ADD_TYPE_INFO)
+ /// }
+ ///
+ /// void Unload(ITypeManager* manager)
+ /// {
+ /// }
+ /// };
+ ///
+ /// // main function
+ ///
+ /// int main()
+ /// {
+ /// LoadPredefinedTypes();
+ /// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
+ /// GetGlobalTypeManager()->Load();
+ /// {
+ /// Dictionary> cs;
+ /// CopyFrom(cs, Range(1, 10)
+ /// .Select([](vint i) -> Pair>
+ /// {
+ /// return { i, MakePtr(i * i) };
+ /// })
+ /// );
+ ///
+ /// Value boxed = BoxParameter>>(cs);
+ /// {
+ /// auto dictionary = UnboxValue>(boxed);
+ /// for (vint i = 0; i < dictionary->GetCount(); i++)
+ /// {
+ /// Value key = dictionary->GetKeys()->Get(i);
+ /// Console::Write(itow(UnboxValue>(dictionary->Get(key))->data) + L" ");
+ /// }
+ /// Console::WriteLine(L"");
+ /// }
+ ///
+ /// for (vint i = 1; i <= 5; i++)
+ /// {
+ /// cs.Remove(i * 2);
+ /// }
+ ///
+ /// {
+ /// for (vint i = 0; i < UnboxValue(boxed.GetProperty(L"Count")); i++)
+ /// {
+ /// Value key = boxed.GetProperty(L"Keys").Invoke(L"Get", (Value_xs(), i));
+ /// Console::Write(itow(UnboxValue(boxed.Invoke(L"Get", (Value_xs(), key)).GetProperty(L"data"))) + L" ");
+ /// }
+ /// Console::WriteLine(L"");
+ /// }
+ /// }
+ /// DestroyGlobalTypeManager();
+ /// }
+ /// ]]>
class IValueDictionary : public virtual IValueReadonlyDictionary, public Description
{
public:
+ /// Replace the value associated to a specified key.
+ /// Returns true if the value is replaced.
+ /// The key to find. If the key does not exist, it will be added to the dictionary.
+ /// The associated value to replace.
virtual void Set(const Value& key, const Value& value) = 0;
+
+ /// Remove a key with the associated value.
+ /// Returns true if the key and the value is removed.
+ /// The key to find.
virtual bool Remove(const Value& key) = 0;
+
+ /// Remove all elements.
virtual void Clear() = 0;
+ /// Create an empty dictionary.
+ /// The created dictionary.
static Ptr Create();
+
+ /// Create a dictionary with elements copied from another readonly dictionary.
+ /// The created dictionary.
+ /// Elements to copy.
static Ptr Create(Ptr values);
+
+ /// Create a dictionary with elements copied from another lazy list.
+ /// The created dictionary.
+ /// Elements to copy.
static Ptr Create(collections::LazyList> values);
};
@@ -1297,20 +3158,36 @@ Interface Implementation Proxy
virtual Value Invoke(IMethodInfo* methodInfo, Ptr arguments) = 0;
};
+ /// A reflectable version of .
+ /// will create a storing a shared pointer to an instance of this interface from a function.
class IValueFunctionProxy : public virtual IDescriptable, public Description
{
public:
+ /// Call the function.
+ /// Return value from the function.
+ /// Arguments to call the function.
virtual Value Invoke(Ptr arguments) = 0;
};
+ /// A reflectable subscription, usually created by the bind expression in Workflow script.
class IValueSubscription : public virtual IDescriptable, public Description
{
typedef void ValueChangedProc(const Value& newValue);
public:
+ /// Event that triggered when the binding source is changed.
+ /// The first argument is the new value of the binding source.
Event ValueChanged;
+ /// Start the subscription.
+ /// Returns true if this operation succeeded.
virtual bool Open() = 0;
+
+ /// Manually trigger the event.
+ /// Returns true if this operation succeeded.
virtual bool Update() = 0;
+
+ /// Stop the subscription.
+ /// Returns true if this operation succeeded.
virtual bool Close() = 0;
};
@@ -1395,11 +3272,8 @@ Runtime Exception
.\GUITYPEDESCRIPTORBUILDER.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Framework::Reflection
-
-Interfaces:
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_GUITYPEDESCRIPTORBUILDER
@@ -1449,6 +3323,14 @@ TypeInfo
{
};
+ /// Get a registered type given a C++ type.
+ /// Returns the metadata class for this registered type.
+ /// The C++ type to get the registered type.
+ ///
+ /// Returning null means the type registration is declared but the type manager has not started.
+ /// Failing to compile means that the type registration is not declared.
+ /// See about how to register a type.
+ ///
template
ITypeDescriptor* GetTypeDescriptor()
{
@@ -2181,7 +4063,7 @@ TypeInfoRetriver Helper Functions (BoxValue, UnboxValue)
return ValueAccessor::Decorator>::BoxValue(object, typeDescriptor);
}
- /// Unbox an reflectable object. Its type cannot be generic.
+ /// Unbox a reflectable object. Its type cannot be generic.
/// The unboxed object.
/// Type of the object.
/// The value to unbox.
@@ -2203,7 +4085,7 @@ TypeInfoRetriver Helper Functions (UnboxParameter)
{
};
- /// Box an reflectable object. It supports generic types such as containers, functions, etc.
+ /// Box an reflectable object. It supports generic types such as containers, functions (should be Func<T>), etc.
/// The boxed value.
/// Type of the object.
/// The object to box.
@@ -2214,7 +4096,7 @@ TypeInfoRetriver Helper Functions (UnboxParameter)
return ParameterAccessor::ResultNonReferenceType, TypeInfoRetriver::TypeFlag>::BoxParameter(object, typeDescriptor);
}
- /// Box an reflectable object. It supports generic types such as containers, functions, etc.
+ /// Box an reflectable object. It supports generic types such as containers, functions (should be Func<T>), etc.
/// Type of the object.
/// The value to unbox.
/// The unboxed object.
@@ -2570,11 +4452,8 @@ StructTypeDescriptor
.\GUITYPEDESCRIPTORBUILDER_CONTAINER.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Framework::Reflection
-
-Interfaces:
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_GUITYPEDESCRIPTORBUILDER_CONTAINER
@@ -2658,12 +4537,20 @@ Enumerable Wrappers
}
};
+ /// Convert a reflectable container to a lazy list to the known element type.
+ /// The created lazy list.
+ /// The expected element type.
+ /// The reflectable container.
template
collections::LazyList GetLazyList(Ptr value)
{
return collections::LazyList(new TypedEnumerator(value));
}
+ /// Convert a reflectable container to a lazy list to the known element type.
+ /// The created lazy list.
+ /// The expected element type.
+ /// The reflectable container.
template
collections::LazyList GetLazyList(Ptr value)
{
@@ -2674,18 +4561,31 @@ Enumerable Wrappers
});
}
+ /// Convert a reflectable container to a lazy list to the known element type.
+ /// The created lazy list.
+ /// The expected element type.
+ /// The reflectable container.
template
collections::LazyList GetLazyList(Ptr value)
{
return GetLazyList(Ptr(value));
}
+ /// Convert a reflectable container to a lazy list to the known element type.
+ /// The created lazy list.
+ /// The expected element type.
+ /// The reflectable container.
template
collections::LazyList GetLazyList(Ptr value)
{
return GetLazyList(Ptr(value));
}
+ /// Convert a reflectable dictionary to a lazy list to the known element type.
+ /// The created lazy list.
+ /// The expected key type.
+ /// The expected value type.
+ /// The reflectable dictionary.
template
collections::LazyList> GetLazyList(Ptr value)
{
@@ -2696,6 +4596,11 @@ Enumerable Wrappers
});
}
+ /// Convert a reflectable dictionary to a lazy list to the known element type.
+ /// The created lazy list.
+ /// The expected key type.
+ /// The expected value type.
+ /// The reflectable dictionary.
template
collections::LazyList> GetLazyList(Ptr value)
{
@@ -3390,6 +5295,31 @@ ParameterAccessor
namespace collections
{
+ /// Base type of observable container which triggers callbacks whenever items are changed.
+ /// Type of elements.
+ /// Type of the key type of elements. It is recommended to use the default value.
+ ///
+ /// Methods are the same to , except that operator[] is readonly.
+ ///
+ /// When an item is being inserted to the list,
+ /// QueryInsert will be called to determine if this item can be inserted,
+ /// BeforeInsert will be called before inserting,
+ /// AfterInsert will be called after inserting.
+ ///
+ ///
+ /// When an item is being removed from the list,
+ /// QueryRemove will be called to determine if this item can be removed,
+ /// BeforeRemove will be called before removing,
+ /// AfterRemove will be called after removing.
+ ///
+ ///
+ /// When an item is being replaced, it is considered as removing the original item and inserting the new item.
+ ///
+ ///
+ /// After any changing happens, NotifyUpdateInternal is called.
+ /// Arguments is exactly the same as .
+ ///
+ ///
template::Type>
class ObservableListBase : public Object, public virtual collections::IEnumerable
{
@@ -3440,6 +5370,20 @@ ParameterAccessor
return items.CreateEnumerator();
}
+ /// Trigger NotifyUpdateInternal manually.
+ /// Returns true if arguments are not out of range.
+ /// The index of the first item that are changed.
+ /// The number of items that are changed, the default value is 1.
+ ///
+ ///
+ /// This is useful when the container is not actually changed, but data in some items are changed.
+ /// For example, in an observable list of shared pointers,
+ /// properties of elements are changed does not trigger callbacks because it doesn't change pointers in the list.
+ ///
+ ///
+ /// If subscribers need to know about such change, calling this function is an easy way to do it.
+ ///
+ ///
bool NotifyUpdate(vint start, vint count = 1)
{
if (start<0 || start >= items.Count() || count <= 0 || start + count>items.Count())
@@ -3585,6 +5529,9 @@ ParameterAccessor
}
};
+ /// An observable container that maintain an implementation of .
+ /// Type of elements.
+ /// Type of the key type of elements. It is recommended to use the default value.
template
class ObservableList : public ObservableListBase
{
@@ -3600,6 +5547,20 @@ ParameterAccessor
}
public:
+ ///
+ /// Get the maintained observable list.
+ /// of the observable list
+ /// will be automatically triggered when any changing happens.
+ ///
+ /// The maintained observable list.
+ ///
+ ///
+ ///
+ /// cannot turn any predefined C++ object to an reflectable observable list
+ /// and keep it binding to the C++ object.
+ /// When an reflectable observable list is required, ObservableList is strongly recommended.
+ ///
+ ///
Ptr GetWrapper()
{
if (!observableList)
@@ -3635,11 +5596,8 @@ ParameterAccessor
.\GUITYPEDESCRIPTORBUILDER_FUNCTION.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Framework::Reflection
-
-Interfaces:
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_GUITYPEDESCRIPTORBUILDER_FUNCTION
@@ -4274,12 +6232,9 @@ CustomEventInfoImpl
/***********************************************************************
.\GUITYPEDESCRIPTORBUILDER_STRUCT.H
***********************************************************************/
-/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Framework::Reflection
-
-Interfaces:
+/*/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_GUITYPEDESCRIPTORBUILDER_STRUCT
@@ -4610,11 +6565,8 @@ ParameterAccessor
.\GUITYPEDESCRIPTORMACROS.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Framework::Reflection
-
-Interfaces:
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_GUITYPEDESCRIPTORMACROS
@@ -5189,11 +7141,8 @@ Property
.\GUITYPEDESCRIPTORREFLECTION.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Framework::Reflection
-
-Interfaces:
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_GUITYPEDESCRIPTORREFLECTION
@@ -5460,6 +7409,8 @@ Helper Functions
LoadPredefinedTypes
***********************************************************************/
+ /// Register all reflectable types in VlppReflection .
+ /// Returns true if this operation succeeded.
extern bool LoadPredefinedTypes();
}
}
diff --git a/Import/VlppRegex.cpp b/Import/VlppRegex.cpp
index b83d8d21..67d8fcd0 100644
--- a/Import/VlppRegex.cpp
+++ b/Import/VlppRegex.cpp
@@ -7,6 +7,11 @@ DEVELOPER: Zihan Chen(vczh)
/***********************************************************************
.\REGEX.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -177,8 +182,6 @@ Regex
}
Regex::Regex(const WString& code, bool preferPure)
- :pure(0)
- ,rich(0)
{
CharRange::List subsets;
RegexExpression::Ref regex=ParseRegexExpression(code);
@@ -770,7 +773,6 @@ RegexLexerColorizer
if ((internalState.interTokenState = token.interTokenState))
{
internalState.interTokenId = token.token;
- internalState.currentState = walker.GetStartState();
}
if (colorize)
{
@@ -814,7 +816,9 @@ RegexLexerColorizer
vint lastFinalStateLength = 0;
vint lastFinalStateToken = -1;
+ vint lastFinalStateState = -1;
+ vint tokenStartState = internalState.currentState;
for (vint i = start; i < length; i++)
{
vint currentToken = -1;
@@ -824,20 +828,27 @@ RegexLexerColorizer
if (previousTokenStop)
{
- internalState.currentState = walker.GetStartState();
if (proc.extendProc && lastFinalStateToken != -1)
{
RegexProcessingToken token(start, lastFinalStateLength, lastFinalStateToken, true, nullptr);
CallExtendProcAndColorizeProc(input, length, token, colorize);
+ if (token.completeToken)
+ {
+ internalState.currentState = walker.GetStartState();
+ }
return start + token.length;
}
else if (i == start)
{
- if (colorize)
+ if (tokenStartState == GetStartState())
{
- proc.colorizeProc(proc.argument, start, 1, -1);
+ if (colorize)
+ {
+ proc.colorizeProc(proc.argument, start, 1, -1);
+ }
+ internalState.currentState = walker.GetStartState();
+ return i + 1;
}
- return i + 1;
}
else
{
@@ -845,6 +856,7 @@ RegexLexerColorizer
{
proc.colorizeProc(proc.argument, start, lastFinalStateLength, lastFinalStateToken);
}
+ internalState.currentState = lastFinalStateState;
return start + lastFinalStateLength;
}
}
@@ -853,6 +865,7 @@ RegexLexerColorizer
{
lastFinalStateLength = i + 1 - start;
lastFinalStateToken = currentToken;
+ lastFinalStateState = internalState.currentState;
}
}
@@ -1009,6 +1022,11 @@ RegexLexer
/***********************************************************************
.\REGEXAUTOMATON.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -1370,6 +1388,11 @@ Helpers
/***********************************************************************
.\REGEXDATA.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -1458,6 +1481,11 @@ CharRange
/***********************************************************************
.\REGEXEXPRESSION.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -2392,6 +2420,11 @@ Expression::Apply
/***********************************************************************
.\REGEXPARSER.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -3090,6 +3123,11 @@ Helper Functions
/***********************************************************************
.\REGEXPURE.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -3322,6 +3360,11 @@ PureInterpretor
/***********************************************************************
.\REGEXRICH.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
@@ -3782,6 +3825,11 @@ RichInterpretor
/***********************************************************************
.\REGEXWRITER.CPP
***********************************************************************/
+/***********************************************************************
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
+***********************************************************************/
+
namespace vl
{
diff --git a/Import/VlppRegex.h b/Import/VlppRegex.h
index 3097e585..47cf41b9 100644
--- a/Import/VlppRegex.h
+++ b/Import/VlppRegex.h
@@ -8,17 +8,8 @@ DEVELOPER: Zihan Chen(vczh)
.\REGEX.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Regex::Regular Expression
-
-Classes:
- RegexString : String Fragment
- RegexMatch : Match Result
- Regex : Regular Expression
- RegexToken : Token
- RegexTokens : Token Stream
- RegexLexer : Tokenizer
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REGEX_REGEX
@@ -42,7 +33,7 @@ namespace vl
Data Structure
***********************************************************************/
- /// A type representing a fragment of the input string.
+ /// A sub string of the string that a is matched against.
class RegexString : public Object
{
protected:
@@ -54,19 +45,19 @@ Data Structure
RegexString(vint _start=0);
RegexString(const WString& _string, vint _start, vint _length);
- /// The position of the input string.
+ /// The position of the input string in characters.
/// The position.
vint Start()const;
- /// The size of the fragment in characters.
+ /// The size of the sub string in characters.
/// The size.
vint Length()const;
- /// Get the fragment.
- /// The fragment.
+ /// Get the sub string as a .
+ /// The sub string.
const WString& Value()const;
bool operator==(const RegexString& string)const;
};
- /// A type representing a match of the input string.
+ /// A match produces by a .
class RegexMatch : public Object, private NotCopyable
{
friend class Regex;
@@ -86,17 +77,43 @@ Data Structure
RegexMatch(const RegexString& _result);
public:
- /// Test if this match is a success match or a failed match. A failed match will only appear when calling [M:vl.regex.Regex.Split] or [M:vl.regex.Regex.Cut]. In other cases, failed matches are either not included in the result, or become null pointers.
- /// Returns true if this match is a success match.
+ ///
+ /// Test if this match is a succeeded match or a failed match.
+ /// A failed match will only appear when calling [M:vl.regex.Regex.Split] or [M:vl.regex.Regex.Cut].
+ /// In other cases, failed matches are either not included in the result.
+ ///
+ /// Returns true if this match is a succeeded match.
bool Success()const;
- /// Get the whole fragment that matches.
- /// The whole fragment.
+ /// Get the matched sub string.
+ /// The matched sub string.
const RegexString& Result()const;
- /// Get all fragments that are captured.
- /// All fragments that are captured.
+ /// Get all sub strings that are captured anonymously.
+ /// All sub strings that are captured anonymously.
+ /// Captures())
+ /// {
+ /// Console::WriteLine(capture.Value());
+ /// }
+ /// }
+ /// ]]>
const CaptureList& Captures()const;
- /// Get all fragments that are captured by named groups.
- /// All fragments that are captured.
+ /// Get all sub strings that are captured by named groups.
+ /// All sub strings that are captured by named groups.
+ /// C/S+)(/.*?))+$");
+ /// auto match = regex.MatchHead(L"C++ and C# are my favorite programing languages");
+ /// FOREACH(RegexString, capture, match->Groups().Get(L"lang"))
+ /// {
+ /// Console::WriteLine(capture.Value());
+ /// }
+ /// }
+ /// ]]>
const CaptureGroup& Groups()const;
};
@@ -104,105 +121,203 @@ Data Structure
Regex
***********************************************************************/
- /// , \^, \$, \!, \=: represents itself
- /// Escaped characters in charset defined in a square bracket:
- /// \r: the CR character
- /// \n: the LF character
- /// \t: the tab character
- /// \-, \[, \], \\, \/, \^, \$: represents itself
- /// 4) Loops:
- /// regex{3}: repeats 3 times
- /// regex{3,}: repeats 3 or more times
- /// regex{1,3}: repeats 1 to 3 times
- /// regex?: repeats 0 or 1 times
- /// regex*: repeats 0 or more times
- /// regex+: repeats 1 or more times
- /// if you add a "?" right after a loop, it means repeating as less as possible (DFA incompatible)
- /// 5) Capturing: (DFA incompatible)
- /// (regex): No capturing, just change the operators' association
- /// (?regex): Capture matched fragment
- /// (regex): Capture matched fragment in a named group called "name"
- /// (<$i>): Match the i-th captured fragment, begins from 0
- /// (<$name;i>): Match the i-th captured fragment in the named group called "name", begins from 0
- /// (<$name>): Match any captured fragment in the named group called "name"
- /// 6) MISC
- /// (=regex): The prefix of the following text should match the regex, but it is not counted in the whole match (DFA incompatible)
- /// (!regex): Any prefix of the following text should not match the regex, and it is not counted in the whole match (DFA incompatible)
- /// (<#name>regex): Name the regex "name", and it applies here
- /// (<&name>): Copy the named regex "name" here and apply
- /// ]]>
+ ///
+ ///
+ /// Regular Expression. Here is a brief description of the regular expression grammar.
+ ///
+ ///
+ ///
+ ///
+ /// Charset :
+ ///
+ /// a , [a-z] , [^a-z]
+ ///
+ ///
+ ///
+ /// Functional characters :
+ ///
+ /// ^ : the beginning of the input (DFA incompatible)
+ /// $ : the end of the input (DFA incompatible)
+ /// regex1|regex2 : match either regex1 or regex2
+ ///
+ ///
+ ///
+ /// Escaping (both \ and / mean the next character is escaped):
+ ///
+ ///
+ /// Escaped characters:
+ ///
+ /// \r : the CR character
+ /// \n : the LF character
+ /// \t : the tab character
+ /// \s : spacing characters (including space, \r, \n, \t)
+ /// \S : non-spacing characters
+ /// \d : [0-9]
+ /// \D : [^0-9]
+ /// \l : [a-zA-Z]
+ /// \L : [^a-zA-Z]
+ /// \w : [a-zA-Z0-9_]
+ /// \W : [^a-zA-Z0-9_]
+ /// \. : any character (this is the main different from other regex, which treat "." as any characters and "\." as the dot character)
+ /// \\ , \/ , \( , \) , \+ , \* , \? , \{ , \} , \[ , \] , \< , \> , \^ , \$ , \! , \= : represents itself
+ ///
+ ///
+ ///
+ /// Escaped characters in charset defined in a square bracket:
+ ///
+ /// \r : the CR character
+ /// \n : the LF character
+ /// \t : the tab character
+ /// \- , \[ , \] , \\ , \/ , \^ , \$ : represents itself
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Loops :
+ ///
+ /// regex{3} : repeats 3 times
+ /// regex{3,} : repeats 3 or more times
+ /// regex{1,3} : repeats 1 to 3 times
+ /// regex? : repeats 0 or 1 times
+ /// regex* : repeats 0 or more times
+ /// regex+ : repeats 1 or more times
+ ///
+ /// if you add an additional ? right after a loop, it means repeating as less as possible (DFA incompatible)
+ ///
+ ///
+ /// Capturing : (DFA incompatible)
+ ///
+ /// (regex) : No capturing, just change the operators' association
+ /// (?regex) : Capture matched fragment
+ /// (<name>regex) : Capture matched fragment in a named group called "name"
+ /// (<$i>) : Match the i-th captured fragment, begins from 0
+ /// (<$name;i>) : Match the i-th captured fragment in the named group called "name", begins from 0
+ /// (<$name>) : Match any captured fragment in the named group called "name"
+ ///
+ ///
+ ///
+ /// MISC
+ ///
+ /// (=regex) : The prefix of the following text should match the regex, but it is not counted in the whole match (DFA incompatible)
+ /// (!regex) : Any prefix of the following text should not match the regex, and it is not counted in the whole match (DFA incompatible)
+ /// (<#name>regex) : Name the regex "name", and it applies here
+ /// (<&name>) : Copy the named regex "name" here and apply
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// The regular expression has pupre mode and rich mode.
+ /// Pure mode means the regular expression is driven by a DFA, while the rich mode is not.
+ ///
+ ///
+ /// The regular expression can test a string instead of matching.
+ /// Testing only returns a bool very indicating success or failure.
+ ///
+ ///
class Regex : public Object, private NotCopyable
{
protected:
- regex_internal::PureInterpretor* pure;
- regex_internal::RichInterpretor* rich;
+ regex_internal::PureInterpretor* pure = nullptr;
+ regex_internal::RichInterpretor* rich = nullptr;
void Process(const WString& text, bool keepEmpty, bool keepSuccess, bool keepFail, RegexMatch::List& matches)const;
public:
- /// Create a regular expression.
+ /// Create a regular expression. It will crash if the regular expression produces syntax error.
/// The regular expression in a string.
- /// Set to true to tell the Regex to use DFA if possible.
- Regex(const WString& code, bool preferPure=true);
+ /// Set to true to use DFA if possible.
+ Regex(const WString& code, bool preferPure = true);
~Regex();
- /// Test does the Regex uses DFA to match a string.
- /// Returns true if DFA is used.
+ /// Test is a DFA used to match a string.
+ /// Returns true if a DFA is used.
bool IsPureMatch()const;
- /// Test does the Regex uses DFA to test a string. Test means ignoring all capturing requirements.
- /// Returns true if DFA is used.
+ /// Test is a DFA used to test a string. It ignores all capturing.
+ /// Returns true if a DFA is used.
bool IsPureTest()const;
/// Match a prefix of the text.
/// Returns the match. Returns null if failed.
/// The text to match.
+ /// Result().Value());
+ /// }
+ /// ]]>
RegexMatch::Ref MatchHead(const WString& text)const;
- /// Match a fragment of the text.
- /// Returns the match. Returns null if failed.
+ /// Match a sub string of the text.
+ /// Returns the first match. Returns null if failed.
/// The text to match.
+ /// Result().Value());
+ /// }
+ /// ]]>
RegexMatch::Ref Match(const WString& text)const;
- /// Match a prefix of the text, ignoring all capturing requirements.
- /// Returns true if succeeded.
+ /// Match a prefix of the text, ignoring all capturing.
+ /// Returns true if it succeeded.
/// The text to match.
bool TestHead(const WString& text)const;
- /// Match a fragment of the text, ignoring all capturing requirements.
+ /// Match a sub string of the text, ignoring all capturing.
/// Returns true if succeeded.
/// The text to match.
bool Test(const WString& text)const;
- /// Find all matched fragments of the text, returning all matched fragments.
+ /// Find all matched fragments in the given text, returning all matched sub strings.
/// The text to match.
- /// All successful matches.
+ /// Returns all succeeded matches.
+ /// , match, matches)
+ /// {
+ /// Console::WriteLine(match->Result().Value());
+ /// }
+ /// }
+ /// ]]>
void Search(const WString& text, RegexMatch::List& matches)const;
- /// Split the text by matched fragments, returning all unmatched fragments.
+ /// Split the text by matched sub strings, returning all unmatched sub strings.
/// The text to match.
- /// Set to true to keep all empty matches.
- /// All failed matches.
+ /// Set to true to keep all empty unmatched sub strings. This could happen when there is nothing between two matched sub strings.
+ /// Returns all failed matches.
+ /// , match, matches)
+ /// {
+ /// Console::WriteLine(match->Result().Value());
+ /// }
+ /// }
+ /// ]]>
void Split(const WString& text, bool keepEmptyMatch, RegexMatch::List& matches)const;
- /// Cut the text by matched fragments, returning all matched or unmatched fragments.
+ /// Cut the text by matched sub strings, returning all matched and unmatched sub strings.
/// The text to match.
- /// Set to true to keep all empty matches.
- /// All successful and failed matches.
+ /// Set to true to keep all empty matches. This could happen when there is nothing between two matched sub strings.
+ /// Returns all succeeded and failed matches.
+ /// , match, matches)
+ /// {
+ /// Console::WriteLine(match->Result().Value());
+ /// }
+ /// }
+ /// ]]>
void Cut(const WString& text, bool keepEmptyMatch, RegexMatch::List& matches)const;
};
@@ -213,17 +328,18 @@ Tokenizer
/// A token.
struct RegexToken
{
- /// Position in the input string.
+ /// Position in the input string in characters.
vint start;
/// Size of this token in characters.
vint length;
- /// The token id, begins at 0, represents the regular expression in the list that matches this token. -1 means this token is produced by an error.
+ /// The token id, begins at 0, represents the regular expression in the list (the first argument in the contructor of ) that matches this token. -1 means this token is produced by an error.
vint token;
/// The pointer to where this token starts in the input string .
+ /// This pointer comes from a that used to be analyzed. You should keep a variable to that string alive, so that to keep this pointer alive.
const wchar_t* reading;
- /// The argument value from [M:vl.regex.RegexLexer.Parse].
+ /// The "codeIndex" argument from [M:vl.regex.RegexLexer.Parse].
vint codeIndex;
- /// True if this token is complete. False if this token does not end here.
+ /// True if this token is complete. False if this token does not end here. This could happend when colorizing a text line by line.
bool completeToken;
/// Row number of the first character, begins at 0.
@@ -248,25 +364,27 @@ Tokenizer
///
const vint start;
///
- /// The length of the token, could be modified after the callback.
+ /// The length of the token, allowing to be updated by the callback.
/// When the callback returns, the length is not allowed to be decreased.
/// This value will be -1 if is not null.
///
vint length;
///
- /// The id of the token, could be modified after the callback.
+ /// The id of the token, allowing to be updated by the callback.
///
vint token;
///
- /// The flag indicating if this token is completed, could be modified after the callback.
+ /// The flag indicating if this token is completed, allowing to be updated by the callback.
///
bool completeToken;
///
- /// The inter token state object, could be modified after the callback.
+ /// The inter token state object, allowing to be updated by the callback.
/// When the callback returns:
- /// if the completeText parameter is true in , it should be nullptr.
- /// if the token does not end at the end of the input, it should not be nullptr.
- /// if a token is completed, it should be nullptr.
+ ///
+ /// if the completeText parameter is true in , it should be nullptr.
+ /// if the token does not end at the end of the input, it should not be nullptr.
+ /// if a token is completed in one attemp of extending, it should be nullptr.
+ ///
///
void* interTokenState;
@@ -288,18 +406,204 @@ Tokenizer
struct RegexProc
{
///
- /// The deleter which deletes inter token state objects created by . This callback is not called automatically.
+ /// The deleter which deletes created by .
+ /// This callback is not called automatically.
+ /// It is here to make the maintainance convenient for the caller.
///
RegexInterTokenStateDeleter deleter = nullptr;
///
- /// The token extend callback. It is called after recognizing any token, and run a customized procedure to modify the token based on the given context.
- /// If the length parameter is -1, it means the caller does not measure the incoming text buffer, which automatically indicates that the buffer is null-terminated.
- /// If the length parameter is not -1, it means the number of available characters in the buffer.
- /// The completeText parameter could be true or false. When it is false, it means that the buffer does not contain all the text.
+ /// The token extend callback. It is called after recognizing any token, and run a customized procedure to modify the token based on the given context.
+ /// If the length parameter is -1, it means the caller does not measure the incoming text buffer, which automatically indicates that the buffer is null-terminated.
+ /// If the length parameter is not -1, it means the number of available characters in the buffer.
+ /// The completeText parameter could be true or false. When it is false, it means that the buffer does not contain all the text.
///
+ ///
+ ///
+ /// This is very useful to recognize any token that cannot be expressed using a regular expression.
+ /// For example, a C++ literal string R"tag(the conteng)tag".
+ /// It is recommended to add a token for R"tag( ,
+ /// and then use this extend proc to search for a )tag" to complete the token.
+ ///
+ ///
+ /// Important :
+ /// when colorizing a text line by line,
+ /// a cross-line token could be incomplete at the end of the line.
+ /// Because a given buffer ends at the end of that line,
+ /// the extend proc is not able to know right now about what is going on in the future.
+ /// Here is what is designed for,
+ /// the extend proc can store anything it wants using that pointer.
+ ///
+ ///
+ /// The caller can get this pointer from the return value of .
+ /// This pointer only available for cross-line tokens, it is obvious that one line produces at most one such pointer.
+ /// Then the caller keeps calling that function to walk throught the whole string.
+ /// When the return value is changed, the pointer is no longer used, and it can be deleted by calling manually.
+ ///
+ ///
+ /// The first argument is .
+ ///
+ ///
+ /// The second argument is a pointer to the buffer of the first character in this token.
+ /// If the previous token is incomplete, then the buffer begins at the first character of the new buffer.
+ ///
+ ///
+ /// The third argument is the length of the recognized token in characters.
+ ///
+ ///
+ /// The fourth character indicates if the token is completed.
+ /// Even if a token is completed, but the extend proc found that, the extend exceeds the end of the buffer,
+ /// then it can update the value to make it incomplete.
+ ///
+ ///
+ /// The fifth contains the context for this token. Fields except "start" are allowed to be updated by the extend proc.
+ ///
+ ///
+ /// tokenDefs;
+ /// tokenDefs.Add(L"/d+");
+ /// tokenDefs.Add(L"[a-zA-Z_]/w*");
+ /// tokenDefs.Add(L"\"([^\"/\\]|/\\/.)*\"");
+ /// tokenDefs.Add(L"R\"[^(]*/(");
+ /// tokenDefs.Add(L"[(){};]");
+ /// tokenDefs.Add(L"/s+");
+ /// tokenDefs.Add(L"///*+([^//*]|/*+[^//])*/*+//");
+ ///
+ /// const wchar_t* lines[] = {
+ /// L"/*********************",
+ /// L"MAIN.CPP",
+ /// L"*********************/",
+ /// L"",
+ /// L"int main()",
+ /// L"{",
+ /// L" printf(\"This is a \\\"simple\\\" text.\");",
+ /// L" printf(R\"____(This is a",
+ /// L"\"multiple lined\"",
+ /// L"literal text)____\");",
+ /// L" return 0;",
+ /// L"}",
+ /// };
+ ///
+ /// struct Argument
+ /// {
+ /// // for a real colorizer, you can put a color buffer here.
+ /// // the buffer is reused for every line of code.
+ /// // but for the demo, I put the current processing text instead.
+ /// // so that I am able to print what is processed.
+ /// const wchar_t* processingText = nullptr;
+ /// } argument;
+ ///
+ /// struct InterTokenState
+ /// {
+ /// WString postfix;
+ /// };
+ ///
+ /// RegexProc proc;
+ /// proc.argument = &argument;
+ /// proc.colorizeProc = [](void* argument, vint start, vint length, vint token)
+ /// {
+ /// // this is guaranteed by "proc.argument = &argument;"
+ /// auto text = reinterpret_cast(argument)->processingText;
+ /// Console::WriteLine(itow(token) + L": <" + WString(text + start, length) + L">");
+ /// };
+ /// proc.deleter = [](void* interTokenState)
+ /// {
+ /// delete reinterpret_cast(interTokenState);
+ /// };
+ /// proc.extendProc = [](void* argument, const wchar_t* reading, vint length, bool completeText, RegexProcessingToken& processingToken)
+ /// {
+ /// // 3 is R"[^(]*/(
+ /// // 7 is not used in tokenDefs, it is occupied to represent an extended literal string
+ /// if (processingToken.token == 3 || processingToken.token == 7)
+ /// {
+ /// // for calling wcsstr, create a buffer that is zero terminated
+ /// WString readingBuffer = length == -1 ? WString(reading, false) : WString(reading, length);
+ /// reading = readingBuffer.Buffer();
+ ///
+ /// // get the postfix, which is )____" in this case
+ /// WString postfix;
+ /// if (processingToken.interTokenState)
+ /// {
+ /// postfix = reinterpret_cast(processingToken.interTokenState)->postfix;
+ /// }
+ /// else
+ /// {
+ /// postfix = L")" + WString(reading + 2, processingToken.length - 3) + L"\"";
+ /// }
+ ///
+ /// // try to find if the postfix, which is )____" in this case, appear in the given buffer
+ /// auto find = wcsstr(reading, postfix.Buffer());
+ /// if (find)
+ /// {
+ /// // if we find the postfix, it means we find the end of the literal string
+ /// // here processingToken.token automatically becomes 7
+ /// // interTokenState needs to be nullptr to indicate this
+ /// processingToken.length = (vint)(find - reading) + postfix.Length();
+ /// processingToken.completeToken = true;
+ /// processingToken.interTokenState = nullptr;
+ /// }
+ /// else
+ /// {
+ /// // if we don't find the postfix, it means the end of the literal string is in future lines
+ /// // we need to set the token to 7, which is the real token id for literal strings
+ /// // since we change any token from 3 to 7, 3 will never be passed to colorizeProc in "token" argument
+ /// processingToken.length = readingBuffer.Length();
+ /// processingToken.token = 7;
+ /// processingToken.completeToken = false;
+ ///
+ /// // we need to ensure that interTokenState is not nullptr, and we can save the postfix here
+ /// if (!completeText && !processingToken.interTokenState)
+ /// {
+ /// auto state = new InterTokenState;
+ /// state->postfix = postfix;
+ /// processingToken.interTokenState = state;
+ /// }
+ /// }
+ /// }
+ /// };
+ ///
+ /// RegexLexer lexer(tokenDefs, proc);
+ /// RegexLexerColorizer colorizer = lexer.Colorize();
+ ///
+ /// void* lastInterTokenState = nullptr;
+ /// FOREACH_INDEXER(const wchar_t*, line, index, From(lines))
+ /// {
+ /// Console::WriteLine(L"Begin line " + itow(index));
+ /// argument.processingText = line;
+ /// void* interTokenState = colorizer.Colorize(line, wcslen(line));
+ ///
+ /// if (lastInterTokenState && lastInterTokenState != interTokenState)
+ /// {
+ /// // call the deleter manually
+ /// proc.deleter(lastInterTokenState);
+ /// }
+ /// lastInterTokenState = interTokenState;
+ ///
+ /// argument.processingText = nullptr;
+ /// colorizer.Pass(L'\r');
+ /// colorizer.Pass(L'\n');
+ /// Console::WriteLine(L"");
+ /// }
+ /// }
+ /// ]]>
RegexTokenExtendProc extendProc = nullptr;
///
+ ///
/// The colorizer callback. It is called when a token is recognized.
+ ///
+ ///
+ /// The first argument is .
+ ///
+ ///
+ /// The second argument is the position of the first character of the token in characters.
+ ///
+ ///
+ /// The third argument is the length of the recognized token in characters.
+ ///
+ ///
+ /// The fourth character is the regular expression in the list (the first argument in the contructor of ) that matches this token.
+ ///
///
RegexTokenColorizeProc colorizeProc = nullptr;
///
@@ -308,7 +612,27 @@ Tokenizer
void* argument = nullptr;
};
- /// Token collection representing the result from the lexical analyzer.
+ /// Token collection representing the result from the lexical analyzer. Call to create this object.
+ /// tokenDefs;
+ /// tokenDefs.Add(L"/d+");
+ /// tokenDefs.Add(L"/w+");
+ /// tokenDefs.Add(L"/s+");
+ ///
+ /// RegexLexer lexer(tokenDefs, {});
+ /// WString input = L"I have 2 books.";
+ /// auto tokenResult = lexer.Parse(input);
+ ///
+ /// FOREACH(RegexToken, token, tokenResult)
+ /// {
+ /// // input must be in a variable
+ /// // because token.reading points to a position from input.Buffer();
+ /// Console::WriteLine(itow(token.token) + L": <" + WString(token.reading, token.length) + L">");
+ /// }
+ /// }
+ /// ]]>
class RegexTokens : public Object, public collections::IEnumerable
{
friend class RegexLexer;
@@ -329,10 +653,96 @@ Tokenizer
/// Copy all tokens.
/// Returns all tokens.
/// A callback to decide which kind of tokens to discard. The input is [F:vl.regex.RegexToken.token]. Returns true to discard this kind of tokens.
+ /// tokenDefs;
+ /// tokenDefs.Add(L"/d+");
+ /// tokenDefs.Add(L"/w+");
+ /// tokenDefs.Add(L"/s+");
+ ///
+ /// RegexLexer lexer(tokenDefs, {});
+ /// WString input = L"I have 2 books.";
+ /// auto tokenResult = lexer.Parse(input);
+ ///
+ /// List filtered;
+ /// tokenResult.ReadToEnd(filtered, [](vint token) { return token < 0 || token == 2; });
+ ///
+ /// FOREACH(RegexToken, token, tokenResult)
+ /// {
+ /// // input must be in a variable
+ /// // because token.reading points to a position from input.Buffer();
+ /// Console::WriteLine(itow(token.token) + L": <" + WString(token.reading, token.length) + L">");
+ /// }
+ /// }
+ /// ]]>
void ReadToEnd(collections::List& tokens, bool(*discard)(vint)=0)const;
};
- /// Lexical walker.
+ /// A type for walking through a text against a . Call to create this object.
+ /// tokenDefs;
+ /// tokenDefs.Add(L"/d+./d+");
+ /// tokenDefs.Add(L"/d+");
+ /// tokenDefs.Add(L"/w+");
+ /// tokenDefs.Add(L"/s+");
+ ///
+ /// RegexLexer lexer(tokenDefs, {});
+ /// RegexLexerWalker walker = lexer.Walk();
+ ///
+ /// WString input = L"This book costs 2.5. That book costs 2.";
+ /// const wchar_t* reading = input.Buffer();
+ ///
+ /// const wchar_t* tokenBegin = reading;
+ /// const wchar_t* tokenEnd = nullptr;
+ /// vint tokenId = -1;
+ ///
+ /// vint state = walker.GetStartState();
+ /// while (*reading)
+ /// {
+ /// vint token = -1;
+ /// bool finalState = false;
+ /// bool previousTokenStop = false;
+ /// walker.Walk(*reading++, state, token, finalState, previousTokenStop);
+ ///
+ /// if (previousTokenStop || !*reading)
+ /// {
+ /// if (tokenEnd)
+ /// {
+ /// if (tokenBegin == tokenEnd)
+ /// {
+ /// Console::WriteLine(L"Recognized token: " + itow(tokenId) + L": <" + WString(*tokenBegin) + L">");
+ /// tokenBegin = reading;
+ /// tokenEnd = nullptr;
+ /// tokenId = -1;
+ /// state = walker.GetStartState();
+ /// }
+ /// else
+ /// {
+ /// Console::WriteLine(L"Recognized token: " + itow(tokenId) + L": <" + WString(tokenBegin, tokenEnd - tokenBegin) + L">");
+ /// tokenBegin = reading = tokenEnd;
+ /// tokenEnd = nullptr;
+ /// tokenId = -1;
+ /// state = walker.GetStartState();
+ /// }
+ /// }
+ /// else
+ /// {
+ /// Console::WriteLine(L"Unrecognized character: <" + WString(*tokenBegin) + L">");
+ /// tokenBegin++;
+ /// state = walker.GetStartState();
+ /// }
+ /// }
+ /// else if (finalState)
+ /// {
+ /// tokenEnd = reading;
+ /// tokenId = token;
+ /// }
+ /// }
+ /// }
+ /// ]]>
class RegexLexerWalker : public Object
{
friend class RegexLexer;
@@ -347,6 +757,7 @@ Tokenizer
/// Get the start DFA state number, which represents the correct state before parsing any input.
/// The DFA state number.
+ /// When calling for the first character, the return value should be passed to the second parameter.
vint GetStartState()const;
/// Test if this state can only lead to the end of one kind of token.
/// Returns the token index if this state can only lead to the end of one kind of token. Returns -1 if not.
@@ -357,25 +768,185 @@ Tokenizer
/// The current state. Returns the new current state when this function returns.
/// Returns the token index at the end of the token.
/// Returns true if it reach the end of the token.
- /// Returns true if the last character is the end of the token.
+ /// Returns true if the previous character is the end of the token.
+ ///
+ ///
+ /// The "finalState" argument is important.
+ /// When "previousTokenStop" becomes true,
+ /// it tells you that this character can no longer form a token with previous consumed characters.
+ /// But it does not mean that the recognized token ends at the previous token.
+ /// The recognized token could end eariler,
+ /// which is indiated at the last time when "finalState" becomes true.
+ ///
+ ///
+ /// See the example for about how to use this function.
+ ///
+ ///
void Walk(wchar_t input, vint& state, vint& token, bool& finalState, bool& previousTokenStop)const;
/// Step forward by one character.
- /// Returns the new current state.
+ /// Returns the new current state. It is used to walk the next character.
/// The input character.
/// The current state.
vint Walk(wchar_t input, vint state)const;
- /// Test if the input text is a complete token.
- /// Returns true if the input text is a complete token.
+ /// Test if the input text is a closed token.
+ /// Returns true if the input text is a closed token.
/// The input text.
/// Size of the input text in characters.
+ ///
+ ///
+ /// A closed token means that,
+ /// there is a prefix that is a recognized token.
+ /// At the same time, the input string itself could not be a token, or a prefix of any token.
+ /// the recognized token has ended before reaching the end of the string.
+ ///
+ ///
+ /// An unrecognized token is also considered as closed.
+ ///
+ ///
+ /// For example, assume we have a token defined by "/d+./d+":
+ ///
+ /// "2" is not a closed token, because it has not ended.
+ ///
+ /// "2.5." is a closed token, because it has ended at "2.5",
+ /// and "2.5." could never be a prefix of any token,
+ /// unless we have another token defined by "/d+./d+./d+".
+ ///
+ ///
+ ///
+ ///
+ /// tokenDefs;
+ /// tokenDefs.Add(L"/d+./d+");
+ /// tokenDefs.Add(L"/d+");
+ ///
+ /// RegexLexer lexer(tokenDefs, {});
+ /// RegexLexerWalker walker = lexer.Walk();
+ ///
+ /// WString tests[] = { L".", L"2", L"2.", L"2.5", L"2.5." };
+ /// FOREACH(WString, test, From(tests))
+ /// {
+ /// if (walker.IsClosedToken(test.Buffer(), test.Length()))
+ /// {
+ /// Console::WriteLine(test + L" is a closed token.");
+ /// }
+ /// else
+ /// {
+ /// Console::WriteLine(test + L" is not a closed token.");
+ /// }
+ /// }
+ /// }
+ /// ]]>
bool IsClosedToken(const wchar_t* input, vint length)const;
- /// Test if the input is a complete token.
- /// Returns true if the input text is a complete token.
+ /// Test if the input is a closed token.
+ /// Returns true if the input text is a closed token.
/// The input text.
+ ///
+ ///
+ /// A closed token means that,
+ /// there is a prefix that is a recognized token.
+ /// At the same time, the input string itself could not be a token, or a prefix of any token.
+ /// the recognized token has ended before reaching the end of the string.
+ ///
+ ///
+ /// An unrecognized token is also considered as closed.
+ ///
+ ///
+ /// For example, assume we have a token defined by "/d+./d+":
+ ///
+ /// "2" is not a closed token, because it has not ended.
+ ///
+ /// "2.5." is a closed token, because it has ended at "2.5",
+ /// and "2.5." could never be a prefix of any token,
+ /// unless we have another token defined by "/d+./d+./d+".
+ ///
+ ///
+ ///
+ ///
+ /// tokenDefs;
+ /// tokenDefs.Add(L"/d+./d+");
+ /// tokenDefs.Add(L"/d+");
+ ///
+ /// RegexLexer lexer(tokenDefs, {});
+ /// RegexLexerWalker walker = lexer.Walk();
+ ///
+ /// WString tests[] = { L".", L"2", L"2.", L"2.5", L"2.5." };
+ /// FOREACH(WString, test, From(tests))
+ /// {
+ /// if (walker.IsClosedToken(test))
+ /// {
+ /// Console::WriteLine(test + L" is a closed token.");
+ /// }
+ /// else
+ /// {
+ /// Console::WriteLine(test + L" is not a closed token.");
+ /// }
+ /// }
+ /// }
+ /// ]]>
bool IsClosedToken(const WString& input)const;
};
- /// Lexical colorizer.
+ /// Lexical colorizer. Call to create this object.
+ /// tokenDefs;
+ /// tokenDefs.Add(L"/d+");
+ /// tokenDefs.Add(L"[a-zA-Z_]/w*");
+ /// tokenDefs.Add(L"[(){};]");
+ /// tokenDefs.Add(L"/s+");
+ /// tokenDefs.Add(L"///*+([^//*]|/*+[^//])*/*+//");
+ ///
+ /// const wchar_t* lines[] = {
+ /// L"/*********************",
+ /// L"MAIN.CPP",
+ /// L"*********************/",
+ /// L"",
+ /// L"int main()",
+ /// L"{",
+ /// L" return 0;",
+ /// L"}",
+ /// };
+ ///
+ /// struct Argument
+ /// {
+ /// // for a real colorizer, you can put a color buffer here.
+ /// // the buffer is reused for every line of code.
+ /// // but for the demo, I put the current processing text instead.
+ /// // so that I am able to print what is processed.
+ /// const wchar_t* processingText = nullptr;
+ /// } argument;
+ ///
+ /// RegexProc proc;
+ /// proc.argument = &argument;
+ /// proc.colorizeProc = [](void* argument, vint start, vint length, vint token)
+ /// {
+ /// // this is guaranteed by "proc.argument = &argument;"
+ /// auto text = reinterpret_cast(argument)->processingText;
+ /// Console::WriteLine(itow(token) + L": <" + WString(text + start, length) + L">");
+ /// };
+ ///
+ /// RegexLexer lexer(tokenDefs, proc);
+ /// RegexLexerColorizer colorizer = lexer.Colorize();
+ ///
+ /// FOREACH_INDEXER(const wchar_t*, line, index, From(lines))
+ /// {
+ /// Console::WriteLine(L"Begin line " + itow(index));
+ /// argument.processingText = line;
+ /// colorizer.Colorize(line, wcslen(line));
+ ///
+ /// argument.processingText = nullptr;
+ /// colorizer.Pass(L'\r');
+ /// colorizer.Pass(L'\n');
+ /// Console::WriteLine(L"");
+ /// }
+ /// }
+ /// ]]>
class RegexLexerColorizer : public Object
{
friend class RegexLexer;
@@ -402,20 +973,38 @@ Tokenizer
/// Get the internal state.
/// The internal state.
+ ///
+ ///
+ /// If has not been called, the return value of this function is the start state.
+ ///
+ ///
+ /// If a text is multi-lined, could be called line by line, and the internal state is changed.
+ ///
+ ///
+ /// In order to colorize another piece of multi-lined text,
+ /// you can either save the start state and call to reset the state,
+ /// or call for a new colorizer.
+ ///
+ ///
InternalState GetInternalState();
- /// Restore the colorizer to a internal state.
- /// The internal state.
+ /// Restore the colorizer to a specified state.
+ /// The state to restore.
void SetInternalState(InternalState state);
/// Step forward by one character.
/// The input character.
+ /// Callbacks in will be called except colorizeProc , which is from the second argument of the constructor of .
void Pass(wchar_t input);
/// Get the start DFA state number, which represents the correct state before colorizing any characters.
/// The DFA state number.
vint GetStartState()const;
- /// Colorize a text. GetCurrentState()const;
- /// An inter token state at the end of this line. It could be the same object which is returned from the previous call.
+ /// Colorize a text.
+ /// An inter token state at the end of this line. It could be the same object to which is returned from the previous call.
/// The text to colorize.
/// Size of the text in characters.
+ ///
+ /// See and for more information about the return value.
+ /// Callbacks in will be called, which is from the second argument of the constructor of .
+ ///
void* Colorize(const wchar_t* input, vint length);
};
@@ -429,18 +1018,19 @@ Tokenizer
RegexProc proc;
public:
- /// Create a lexical analyzer by a set of regular expressions. [F:vl.regex.RegexToken.token] will be the index of the matched regular expression.
- /// The regular expressions.
- /// Callback procedures.
+ /// Create a lexical analyzer by a set of regular expressions. [F:vl.regex.RegexToken.token] will be the index of the matched regular expression in the first argument.
+ /// ALl regular expression, each one represent a kind of tokens.
+ /// Configuration of all callbacks.
RegexLexer(const collections::IEnumerable& tokens, RegexProc _proc);
~RegexLexer();
- /// Tokenize a input text.
- /// The result.
+ /// Tokenize an input text.
+ /// All tokens, including recognized tokens or unrecognized tokens. For unrecognized tokens, [F:vl.regex.RegexToken.token] will be -1.
/// The text to tokenize.
- /// Extra information that will store in [F:vl.regex.RegexToken.codeIndex].
+ /// Extra information that will be copied to [F:vl.regex.RegexToken.codeIndex].
+ /// Callbacks in will be called when iterating through tokens, which is from the second argument of the constructor of .
RegexTokens Parse(const WString& code, vint codeIndex=-1)const;
- /// Create a equivalence walker from this lexical analyzer.
+ /// Create a equivalence walker from this lexical analyzer. A walker enable you to walk throught characters one by one,
/// The walker.
RegexLexerWalker Walk()const;
/// Create a equivalence colorizer from this lexical analyzer.
@@ -456,11 +1046,8 @@ Tokenizer
.\REGEXDATA.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Regex::Basic Data Structure
-
-Classes:
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REGEX_REGEXDATA
@@ -516,18 +1103,8 @@ Data Structure
.\REGEXAUTOMATON.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Regex::RegexAutomaton
-
-Classes:
- State : State
- Transition : Transation
- Automaton : Automaton
-
-Functions:
- EpsilonNfaToNfa : Copy and remove epsilon states and transitions from an NFA
- NfaToDfa : Convert an NFA to a DFA
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REGEX_REGEXAUTOMATON
@@ -617,9 +1194,8 @@ namespace vl
.\REGEXEXPRESSION.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Regex::RegexExpression
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
Classes:
Expression : Base class of expressions |
@@ -1000,12 +1576,8 @@ Helper Functions
.\REGEXPURE.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Regex::RegexInterpretor
-
-Classes:
- PureInterpretor : Pure regular expression interpretor
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REGEX_REGEXPURE
@@ -1065,12 +1637,8 @@ namespace vl
.\REGEXRICH.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Regex::RegexInterpretor
-
-Classes:
- RichInterpretor : Rich regular expression interpretor
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REGEX_REGEXRICH
@@ -1137,11 +1705,8 @@ namespace vl
.\REGEXWRITER.H
***********************************************************************/
/***********************************************************************
-Vczh Library++ 3.0
-Developer: Zihan Chen(vczh)
-Regex::RegexWriter
-
-Classes:
+Author: Zihan Chen (vczh)
+Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REGEX_REGEXWRITER
diff --git a/Tools/CppMerge.exe b/Tools/CppMerge.exe
index 546234df..d3cb95ac 100644
Binary files a/Tools/CppMerge.exe and b/Tools/CppMerge.exe differ
diff --git a/Tools/GacGen32.exe b/Tools/GacGen32.exe
index c064797e..20adb771 100644
Binary files a/Tools/GacGen32.exe and b/Tools/GacGen32.exe differ
diff --git a/Tools/GacGen64.exe b/Tools/GacGen64.exe
index 1b031d07..b65dfcce 100644
Binary files a/Tools/GacGen64.exe and b/Tools/GacGen64.exe differ
diff --git a/Tools/ParserGen.exe b/Tools/ParserGen.exe
new file mode 100644
index 00000000..a987ffe6
Binary files /dev/null and b/Tools/ParserGen.exe differ
diff --git a/Tools/StartProcess.ps1 b/Tools/StartProcess.ps1
index 2cc21884..2653c615 100644
--- a/Tools/StartProcess.ps1
+++ b/Tools/StartProcess.ps1
@@ -1,4 +1,4 @@
-function Start-Process-And-Wait([String[][]] $Pairs, [Boolean]$Inline = $false, [String]$workingDirectory = "") {
+function Start-Process-And-Wait([String[][]] $Pairs, [Boolean]$Inline = $false, [String]$WorkingDirectory = "", [Boolean]$ThrowOnCrash = $true) {
$processes = New-Object System.Diagnostics.Process[] $Pairs.Length
for ($i = 0; $i -lt $Pairs.Length; $i++) {
Write-Host " Running: $($Pairs[$i][0]) $($Pairs[$i][1])" -ForegroundColor DarkGray
@@ -9,8 +9,8 @@ function Start-Process-And-Wait([String[][]] $Pairs, [Boolean]$Inline = $false,
}
$arguments.Add("PassThru", $true)
$arguments.Add("NoNewWindow", $Inline)
- if ($workingDirectory -ne "") {
- $arguments.Add("WorkingDirectory", $workingDirectory)
+ if ($WorkingDirectory -ne "") {
+ $arguments.Add("WorkingDirectory", $WorkingDirectory)
}
$processes[$i] = Start-Process $Pairs[$i][0] @arguments
@@ -21,7 +21,7 @@ function Start-Process-And-Wait([String[][]] $Pairs, [Boolean]$Inline = $false,
$process = $processes[$i]
$process_handle = $process.Handle
$process.WaitForExit()
- if ($process.ExitCode -ne 0) {
+ if (($process.ExitCode -ne 0) -and $ThrowOnCrash) {
Write-Host " Crashes($($process.ExitCode)): $($Pairs[$i][0]) $($Pairs[$i][1])" -ForegroundColor Red
$failed = $true
}
diff --git a/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x64 b/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x64
index 609e4289..d953afb9 100644
Binary files a/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x64 and b/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x64 differ
diff --git a/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x86 b/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x86
index f1acc50b..1c119b57 100644
Binary files a/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x86 and b/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x86 differ