mirror of
https://github.com/vczh-libraries/Release.git
synced 2026-02-06 03:42:11 +08:00
3700 lines
137 KiB
C++
3700 lines
137 KiB
C++
/***********************************************************************
|
|
THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY
|
|
DEVELOPER: Zihan Chen(vczh)
|
|
***********************************************************************/
|
|
#include "Vlpp.h"
|
|
|
|
/***********************************************************************
|
|
.\HTTPUTILITY.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_HTTPUTILITY
|
|
#define VCZH_HTTPUTILITY
|
|
|
|
|
|
#ifdef VCZH_MSVC
|
|
|
|
namespace vl
|
|
{
|
|
|
|
/***********************************************************************
|
|
HTTP Utility
|
|
***********************************************************************/
|
|
|
|
/// <summary>An http requiest.</summary>
|
|
class HttpRequest
|
|
{
|
|
typedef collections::Array<char> BodyBuffer;
|
|
typedef collections::List<WString> StringList;
|
|
typedef collections::Dictionary<WString, WString> HeaderMap;
|
|
public:
|
|
/// <summary>Name of the server, like "gaclib.net".</summary>
|
|
WString server;
|
|
/// <summary>Port of the server, like 80.</summary>
|
|
vint port = 0;
|
|
/// <summary>Query of the request, like "/index.html".</summary>
|
|
WString query;
|
|
/// <summary>Set to true if the request uses SSL, or https.</summary>
|
|
bool secure = false;
|
|
/// <summary>User name to authorize. Set to empty if authorization is not needed.</summary>
|
|
WString username;
|
|
/// <summary>Password to authorize. Set to empty if authorization is not needed.</summary>
|
|
WString password;
|
|
/// <summary>HTTP method, like "GET", "POST", "PUT", "DELETE", etc.</summary>
|
|
WString method;
|
|
/// <summary>Cookie. Set to empty if cookie is not needed.</summary>
|
|
WString cookie;
|
|
/// <summary>Request body. This is a byte array.</summary>
|
|
BodyBuffer body;
|
|
/// <summary>Content type, like "text/xml".</summary>
|
|
WString contentType;
|
|
/// <summary>Accept type list, elements like "text/xml".</summary>
|
|
StringList acceptTypes;
|
|
/// <summary>A dictionary to contain extra headers.</summary>
|
|
HeaderMap extraHeaders;
|
|
|
|
/// <summary>Create an empty request.</summary>
|
|
HttpRequest() = default;
|
|
|
|
/// <summary>Set <see cref="server"/>, <see cref="port"/>, <see cref="query"/> and <see cref="secure"/> fields for you using an URL.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="inputQuery">The URL.</param>
|
|
bool SetHost(const WString& inputQuery);
|
|
|
|
/// <summary>Fill the text body in UTF-8.</summary>
|
|
/// <param name="bodyString">The text to fill.</param>
|
|
void SetBodyUtf8(const WString& bodyString);
|
|
};
|
|
|
|
/// <summary>A type representing an http response.</summary>
|
|
class HttpResponse
|
|
{
|
|
typedef collections::Array<char> BodyBuffer;
|
|
public:
|
|
/// <summary>Status code, like 200.</summary>
|
|
vint statusCode = 0;
|
|
/// <summary>Response body. This is a byte array.</summary>
|
|
BodyBuffer body;
|
|
/// <summary>Returned cookie from the server.</summary>
|
|
WString cookie;
|
|
|
|
HttpResponse() = default;
|
|
|
|
/// <summary>Get the text body, encoding is assumed to be UTF-8.</summary>
|
|
/// <returns>The response body as text.</returns>
|
|
WString GetBodyUtf8();
|
|
};
|
|
|
|
/// <summary>Send an http request and receive a response.</summary>
|
|
/// <returns>Returns true if this operation succeeded, even when the server returns 404.</returns>
|
|
/// <param name="request">The request to send.</param>
|
|
/// <param name="response">Returns the response.</param>
|
|
/// <remarks>
|
|
/// <p>
|
|
/// This function will block the calling thread until the respons is returned.
|
|
/// </p>
|
|
/// <p>
|
|
/// This function is only available in Windows.
|
|
/// </p>
|
|
/// </remarks>
|
|
/// <example><![CDATA[
|
|
/// int main()
|
|
/// {
|
|
/// HttpRequest request;
|
|
/// HttpResponse response;
|
|
/// request.SetHost(L"http://www.msftncsi.com/ncsi.txt");
|
|
/// HttpQuery(request, response);
|
|
/// Console::WriteLine(L"Status:" + itow(response.statusCode));
|
|
/// Console::WriteLine(L"Body:" + response.GetBodyUtf8());
|
|
/// }
|
|
/// ]]></example>
|
|
extern bool HttpQuery(const HttpRequest& request, HttpResponse& response);
|
|
|
|
/// <summary>Encode a text as part of the url. This function can be used to create arguments in an URL.</summary>
|
|
/// <returns>The encoded text.</returns>
|
|
/// <param name="query">The text to encode.</param>
|
|
/// <remarks>
|
|
/// <p>
|
|
/// 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.
|
|
/// </p>
|
|
/// <p>
|
|
/// This function is only available in Windows.
|
|
/// </p>
|
|
///</remarks>
|
|
extern WString UrlEncodeQuery(const WString& query);
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
/***********************************************************************
|
|
.\LOCALE.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_LOCALE
|
|
#define VCZH_LOCALE
|
|
|
|
|
|
namespace vl
|
|
{
|
|
/***********************************************************************
|
|
Locale
|
|
***********************************************************************/
|
|
|
|
/// <summary>Locale awared operations. Macro "INVLOC" is a shortcut to get a invariant locale.</summary>
|
|
/// <remarks>
|
|
/// <p>
|
|
/// For all string operations that the normalization does not set to <b>None</b>,
|
|
/// 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.
|
|
/// </p>
|
|
/// <p>
|
|
/// In Linux and macOS, only en-US is supported, with a hard-coded set of date and time formats,
|
|
/// and string operations only support <b>None</b> and <b>IgnoreCase</b> for normalization.
|
|
/// </p>
|
|
/// </remarks>
|
|
class Locale : public Object
|
|
{
|
|
protected:
|
|
WString localeName;
|
|
|
|
public:
|
|
/// <summary>Create a locale with a specified local name.</summary>
|
|
/// <param name="_localeName">The name of the locale. If it is not provided, it becomes the invariant locale.</param>
|
|
/// <remarks>
|
|
/// In Windows, the specified locale need to be installed in order to take effect.
|
|
/// In Linux and macOS, only en-US is supported.
|
|
/// </remarks>
|
|
Locale() = default;
|
|
Locale(const Locale&) = default;
|
|
Locale(Locale&&) = default;
|
|
~Locale() = default;
|
|
|
|
Locale& operator=(const Locale&) = default;
|
|
Locale& operator=(Locale&&) = default;
|
|
|
|
Locale(const WString& _localeName);
|
|
|
|
std::strong_ordering operator<=>(const Locale& locale)const { return localeName <=> locale.localeName; }
|
|
bool operator==(const Locale& locale)const { return localeName == locale.localeName; }
|
|
|
|
/// <summary>Get the invariant locale. An invariant locale is neutral, it is not awared of any language specified thing.</summary>
|
|
/// <returns>The invariant locale.</returns>
|
|
static Locale Invariant();
|
|
/// <summary>Get the system default locale. This locale controls the code page that used by the the system to interpret ANSI string buffers.</summary>
|
|
/// <returns>The system default locale.</returns>
|
|
static Locale SystemDefault();
|
|
/// <summary>Get the user default locale. This locale reflect the user's settings and UI language.</summary>
|
|
/// <returns>The user default locale.</returns>
|
|
static Locale UserDefault();
|
|
/// <summary>Get all supported locales.</summary>
|
|
/// <param name="locales">All supported locales.</param>
|
|
static void Enumerate(collections::List<Locale>& locales);
|
|
|
|
/// <summary>Get the name of this locale.</summary>
|
|
/// <returns>The name of this locale.</returns>
|
|
const WString& GetName()const;
|
|
|
|
/// <summary>Get all short date formats for this locale.</summary>
|
|
/// <param name="formats">Returns all formats.</param>
|
|
void GetShortDateFormats(collections::List<WString>& formats)const;
|
|
/// <summary>Get all long date formats for this locale.</summary>
|
|
/// <param name="formats">Returns all formats.</param>
|
|
void GetLongDateFormats(collections::List<WString>& formats)const;
|
|
/// <summary>Get all Year-Month date formats for this locale.</summary>
|
|
/// <param name="formats">Returns all formats.</param>
|
|
void GetYearMonthDateFormats(collections::List<WString>& formats)const;
|
|
/// <summary>Get all long time formats for this locale.</summary>
|
|
/// <param name="formats">Returns all formats.</param>
|
|
void GetLongTimeFormats(collections::List<WString>& formats)const;
|
|
/// <summary>Get all short time formats for this locale.</summary>
|
|
/// <param name="formats">Returns all formats.</param>
|
|
void GetShortTimeFormats(collections::List<WString>& formats)const;
|
|
|
|
/// <summary>Convert a date to a formatted string.</summary>
|
|
/// <returns>The formatted string.</returns>
|
|
/// <param name="format">The format to use.</param>
|
|
/// <param name="date">The date to convert.</param>
|
|
/// <remarks>
|
|
/// The value of the "format" argument must come from any of the following functions.
|
|
/// Otherwise the behavior is undefined.
|
|
/// <ul>
|
|
/// <li><see cref="GetShortDateFormats"/></li>
|
|
/// <li><see cref="GetLongDateFormats"/></li>
|
|
/// <li><see cref="GetYearMonthDateFormats"/></li>
|
|
/// </ul>
|
|
/// </remarks>
|
|
WString FormatDate(const WString& format, DateTime date)const;
|
|
/// <summary>Convert a time to a formatted string.</summary>
|
|
/// <returns>The formatted string.</returns>
|
|
/// <param name="format">The format to use.</param>
|
|
/// <param name="time">The time to convert.</param>
|
|
/// <remarks>
|
|
/// The value of the "format" argument must come from any of the following functions.
|
|
/// Otherwise the behavior is undefined.
|
|
/// <ul>
|
|
/// <li><see cref="GetLongTimeFormats"/></li>
|
|
/// <li><see cref="GetShortTimeFormats"/></li>
|
|
/// </ul>
|
|
/// </remarks>
|
|
WString FormatTime(const WString& format, DateTime time)const;
|
|
|
|
/// <summary>Convert a number to a formatted string according to the locale.</summary>
|
|
/// <returns>The formatted string.</returns>
|
|
/// <param name="number">The number to convert.</param>
|
|
WString FormatNumber(const WString& number)const;
|
|
/// <summary>Convert a currency (money) to a formatted string according to the locale.</summary>
|
|
/// <returns>The formatted string.</returns>
|
|
/// <param name="currency">The currency to convert.</param>
|
|
WString FormatCurrency(const WString& currency)const;
|
|
|
|
/// <summary>Get the short display string of a day of week according to the locale.</summary>
|
|
/// <returns>The display string.</returns>
|
|
/// <param name="dayOfWeek">Day of week, begins from 0 as Sunday.</param>
|
|
WString GetShortDayOfWeekName(vint dayOfWeek)const;
|
|
/// <summary>Get the long display string of a day of week according to the locale.</summary>
|
|
/// <returns>The display string.</returns>
|
|
/// <param name="dayOfWeek">Day of week, begins from 0 as Sunday.</param>
|
|
WString GetLongDayOfWeekName(vint dayOfWeek)const;
|
|
/// <summary>Get the short display string of a month according to the locale.</summary>
|
|
/// <returns>The display string.</returns>
|
|
/// <param name="month">Month, begins from 1 as January.</param>
|
|
WString GetShortMonthName(vint month)const;
|
|
/// <summary>Get the long display string of a month according to the locale.</summary>
|
|
/// <returns>The display string.</returns>
|
|
/// <param name="month">Month, begins from 1 as January.</param>
|
|
WString GetLongMonthName(vint month)const;
|
|
|
|
#ifdef VCZH_MSVC
|
|
/// <summary>Convert characters to the full width.</summary>
|
|
/// <returns>The converted string.</returns>
|
|
/// <param name="str">The string to convert.</param>
|
|
/// <remarks>This function is only available in Windows.</remarks>
|
|
WString ToFullWidth(const WString& str)const;
|
|
/// <summary>Convert characters to the half width.</summary>
|
|
/// <returns>The converted string.</returns>
|
|
/// <param name="str">The string to convert.</param>
|
|
/// <remarks>This function is only available in Windows.</remarks>
|
|
WString ToHalfWidth(const WString& str)const;
|
|
/// <summary>Convert characters to the Hiragana.</summary>
|
|
/// <returns>The converted string.</returns>
|
|
/// <param name="str">The string to convert.</param>
|
|
/// <remarks>This function is only available in Windows.</remarks>
|
|
WString ToHiragana(const WString& str)const;
|
|
/// <summary>Convert characters to the Katagana.</summary>
|
|
/// <returns>The converted string.</returns>
|
|
/// <param name="str">The string to convert.</param>
|
|
/// <remarks>This function is only available in Windows.</remarks>
|
|
WString ToKatagana(const WString& str)const;
|
|
#endif
|
|
|
|
/// <summary>Convert characters to the lower case using the file system rule.</summary>
|
|
/// <returns>The converted string.</returns>
|
|
/// <param name="str">The string to convert.</param>
|
|
WString ToLower(const WString& str)const;
|
|
/// <summary>Convert characters to the upper case using the file system rule.</summary>
|
|
/// <returns>The converted string.</returns>
|
|
/// <param name="str">The string to convert.</param>
|
|
WString ToUpper(const WString& str)const;
|
|
/// <summary>Convert characters to the lower case using the linguistic rule.</summary>
|
|
/// <returns>The converted string.</returns>
|
|
/// <param name="str">The string to convert.</param>
|
|
WString ToLinguisticLower(const WString& str)const;
|
|
/// <summary>Convert characters to the upper case using the linguistic rule.</summary>
|
|
/// <returns>The converted string.</returns>
|
|
/// <param name="str">The string to convert.</param>
|
|
WString ToLinguisticUpper(const WString& str)const;
|
|
|
|
#ifdef VCZH_MSVC
|
|
/// <summary>Convert characters to Simplified Chinese.</summary>
|
|
/// <returns>The converted string.</returns>
|
|
/// <param name="str">The string to convert.</param>
|
|
/// <remarks>This function is only available in Windows.</remarks>
|
|
WString ToSimplifiedChinese(const WString& str)const;
|
|
/// <summary>Convert characters to the Traditional Chinese.</summary>
|
|
/// <returns>The converted string.</returns>
|
|
/// <param name="str">The string to convert.</param>
|
|
/// <remarks>This function is only available in Windows.</remarks>
|
|
WString ToTraditionalChinese(const WString& str)const;
|
|
/// <summary>Convert characters to the tile case, in which the first letter of each major word is capitalized.</summary>
|
|
/// <returns>The converted string.</returns>
|
|
/// <param name="str">The string to convert.</param>
|
|
/// <remarks>This function is only available in Windows.</remarks>
|
|
WString ToTileCase(const WString& str)const;
|
|
#endif
|
|
|
|
/// <summary>Mergable flags controlling how to normalize a string.</summary>
|
|
enum Normalization
|
|
{
|
|
/// <summary>Do nothing.</summary>
|
|
None=0,
|
|
/// <summary>Ignore case using the file system rule.</summary>
|
|
IgnoreCase=1,
|
|
#ifdef VCZH_MSVC
|
|
/// <summary>Ignore case using the linguistic rule. This value is only available in Windows.</summary>
|
|
IgnoreCaseLinguistic=2,
|
|
/// <summary>Ignore the difference between between hiragana and katakana characters. This value is only available in Windows.</summary>
|
|
IgnoreKanaType=4,
|
|
/// <summary>Ignore nonspacing characters. This value is only available in Windows.</summary>
|
|
IgnoreNonSpace=8,
|
|
/// <summary>Ignore symbols and punctuation. This value is only available in Windows.</summary>
|
|
IgnoreSymbol=16,
|
|
/// <summary>Ignore the difference between half-width and full-width characters. This value is only available in Windows.</summary>
|
|
IgnoreWidth=32,
|
|
/// <summary>Treat digits as numbers during sorting. This value is only available in Windows.</summary>
|
|
DigitsAsNumbers=64,
|
|
/// <summary>Treat punctuation the same as symbols. This value is only available in Windows.</summary>
|
|
StringSoft=128,
|
|
#endif
|
|
};
|
|
|
|
/// <summary>Compare two strings.</summary>
|
|
/// <returns>Returns 0 if two strings are equal. Returns a positive number if the first string is larger. Returns a negative number if the second string is larger. When sorting strings, larger strings are put after then smaller strings.</returns>
|
|
/// <param name="s1">The first string to compare.</param>
|
|
/// <param name="s2">The second string to compare.</param>
|
|
/// <param name="normalization">Flags controlling how to normalize a string.</param>
|
|
vint Compare(const WString& s1, const WString& s2, Normalization normalization)const;
|
|
/// <summary>Compare two strings to test binary equivalence.</summary>
|
|
/// <returns>Returns 0 if two strings are equal. Returns a positive number if the first string is larger. Returns a negative number if the second string is larger. When sorting strings, larger strings are put after then smaller strings.</returns>
|
|
/// <param name="s1">The first string to compare.</param>
|
|
/// <param name="s2">The second string to compare.</param>
|
|
vint CompareOrdinal(const WString& s1, const WString& s2)const;
|
|
/// <summary>Compare two strings to test binary equivalence, ignoring case.</summary>
|
|
/// <returns>Returns 0 if two strings are equal. Returns a positive number if the first string is larger. Returns a negative number if the second string is larger. When sorting strings, larger strings are put after then smaller strings.</returns>
|
|
/// <param name="s1">The first string to compare.</param>
|
|
/// <param name="s2">The second string to compare.</param>
|
|
vint CompareOrdinalIgnoreCase(const WString& s1, const WString& s2)const;
|
|
/// <summary>Find the first position that the sub string appears in a text.</summary>
|
|
/// <returns>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.</returns>
|
|
/// <param name="text">The text to find the sub string.</param>
|
|
/// <param name="find">The sub string to match.</param>
|
|
/// <param name="normalization">Flags controlling how to normalize a string.</param>
|
|
/// <remarks>For any normalization that is not <b>None</b>, the found sub string could be different to the string you want to find.</remarks>
|
|
collections::Pair<vint, vint> FindFirst(const WString& text, const WString& find, Normalization normalization)const;
|
|
/// <summary>Find the last position that the sub string appears in a text.</summary>
|
|
/// <returns>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.</returns>
|
|
/// <param name="text">The text to find the sub string.</param>
|
|
/// <param name="find">The sub string to match.</param>
|
|
/// <param name="normalization">Flags controlling how to normalize a string.</param>
|
|
/// <remarks>For any normalization that is not <b>None</b>, the found sub string could be different to the string you want to find.</remarks>
|
|
collections::Pair<vint, vint> FindLast(const WString& text, const WString& find, Normalization normalization)const;
|
|
/// <summary>Test is the prefix of the text equivalence to the provided sub string.</summary>
|
|
/// <returns>Returns true if the prefix of the text equivalence to the provided sub string.</returns>
|
|
/// <param name="text">The text to test the prefix.</param>
|
|
/// <param name="find">The sub string to match.</param>
|
|
/// <param name="normalization">Flags controlling how to normalize a string.</param>
|
|
/// <remarks>For any normalization that is not <b>None</b>, the found prefix could be different to the string you want to find.</remarks>
|
|
bool StartsWith(const WString& text, const WString& find, Normalization normalization)const;
|
|
/// <summary>Test is the postfix of the text equivalence to the provided sub string.</summary>
|
|
/// <returns>Returns true if the postfix of the text equivalence to the provided sub string.</returns>
|
|
/// <param name="text">The text to test the postfix.</param>
|
|
/// <param name="find">The sub string to match.</param>
|
|
/// <param name="normalization">Flags controlling how to normalize a string.</param>
|
|
/// <remarks>For any normalization that is not <b>None</b>, the postfix could be different to the string you want to find.</remarks>
|
|
bool EndsWith(const WString& text, const WString& find, Normalization normalization)const;
|
|
};
|
|
|
|
#define INVLOC vl::Locale::Invariant()
|
|
|
|
/***********************************************************************
|
|
ILocaleImpl
|
|
***********************************************************************/
|
|
|
|
/// <summary>Platform-specific locale implementation interface.</summary>
|
|
class ILocaleImpl : public virtual feature_injection::IFeatureImpl
|
|
{
|
|
public:
|
|
virtual Locale Invariant() const = 0;
|
|
virtual Locale SystemDefault() const = 0;
|
|
virtual Locale UserDefault() const = 0;
|
|
virtual void Enumerate(collections::List<Locale>& locales) const = 0;
|
|
|
|
virtual void GetShortDateFormats(const WString& localeName, collections::List<WString>& formats) const = 0;
|
|
virtual void GetLongDateFormats(const WString& localeName, collections::List<WString>& formats) const = 0;
|
|
virtual void GetYearMonthDateFormats(const WString& localeName, collections::List<WString>& formats) const = 0;
|
|
virtual void GetLongTimeFormats(const WString& localeName, collections::List<WString>& formats) const = 0;
|
|
virtual void GetShortTimeFormats(const WString& localeName, collections::List<WString>& formats) const = 0;
|
|
|
|
virtual WString FormatDate(const WString& localeName, const WString& format, DateTime date) const = 0;
|
|
virtual WString FormatTime(const WString& localeName, const WString& format, DateTime time) const = 0;
|
|
virtual WString FormatNumber(const WString& localeName, const WString& number) const = 0;
|
|
virtual WString FormatCurrency(const WString& localeName, const WString& currency) const = 0;
|
|
|
|
virtual WString GetShortDayOfWeekName(const WString& localeName, vint dayOfWeek) const = 0;
|
|
virtual WString GetLongDayOfWeekName(const WString& localeName, vint dayOfWeek) const = 0;
|
|
virtual WString GetShortMonthName(const WString& localeName, vint month) const = 0;
|
|
virtual WString GetLongMonthName(const WString& localeName, vint month) const = 0;
|
|
|
|
virtual WString ToLower(const WString& localeName, const WString& str) const = 0;
|
|
virtual WString ToUpper(const WString& localeName, const WString& str) const = 0;
|
|
virtual WString ToLinguisticLower(const WString& localeName, const WString& str) const = 0;
|
|
virtual WString ToLinguisticUpper(const WString& localeName, const WString& str) const = 0;
|
|
|
|
virtual vint Compare(const WString& localeName, const WString& s1, const WString& s2, Locale::Normalization normalization) const = 0;
|
|
virtual vint CompareOrdinal(const WString& s1, const WString& s2) const = 0;
|
|
virtual vint CompareOrdinalIgnoreCase(const WString& s1, const WString& s2) const = 0;
|
|
virtual collections::Pair<vint, vint> FindFirst(const WString& localeName, const WString& text, const WString& find, Locale::Normalization normalization) const = 0;
|
|
virtual collections::Pair<vint, vint> FindLast(const WString& localeName, const WString& text, const WString& find, Locale::Normalization normalization) const = 0;
|
|
virtual bool StartsWith(const WString& localeName, const WString& text, const WString& find, Locale::Normalization normalization) const = 0;
|
|
virtual bool EndsWith(const WString& localeName, const WString& text, const WString& find, Locale::Normalization normalization) const = 0;
|
|
};
|
|
|
|
extern void InjectLocaleImpl(ILocaleImpl* impl);
|
|
extern void EjectLocaleImpl(ILocaleImpl* impl);
|
|
|
|
/***********************************************************************
|
|
EnUsLocaleImpl
|
|
***********************************************************************/
|
|
|
|
/// <summary>A platform independent implementation that only supports en-US.</summary>
|
|
class EnUsLocaleImpl : public feature_injection::FeatureImpl<ILocaleImpl>
|
|
{
|
|
public:
|
|
Locale Invariant() const override;
|
|
Locale SystemDefault() const override;
|
|
Locale UserDefault() const override;
|
|
void Enumerate(collections::List<Locale>& locales) const override;
|
|
|
|
void GetShortDateFormats(const WString& localeName, collections::List<WString>& formats) const override;
|
|
void GetLongDateFormats(const WString& localeName, collections::List<WString>& formats) const override;
|
|
void GetYearMonthDateFormats(const WString& localeName, collections::List<WString>& formats) const override;
|
|
void GetLongTimeFormats(const WString& localeName, collections::List<WString>& formats) const override;
|
|
void GetShortTimeFormats(const WString& localeName, collections::List<WString>& formats) const override;
|
|
|
|
WString FormatDate(const WString& localeName, const WString& format, DateTime date) const override;
|
|
WString FormatTime(const WString& localeName, const WString& format, DateTime time) const override;
|
|
WString FormatNumber(const WString& localeName, const WString& number) const override;
|
|
WString FormatCurrency(const WString& localeName, const WString& currency) const override;
|
|
|
|
WString GetShortDayOfWeekName(const WString& localeName, vint dayOfWeek) const override;
|
|
WString GetLongDayOfWeekName(const WString& localeName, vint dayOfWeek) const override;
|
|
WString GetShortMonthName(const WString& localeName, vint month) const override;
|
|
WString GetLongMonthName(const WString& localeName, vint month) const override;
|
|
|
|
WString ToLower(const WString& localeName, const WString& str) const override;
|
|
WString ToUpper(const WString& localeName, const WString& str) const override;
|
|
WString ToLinguisticLower(const WString& localeName, const WString& str) const override;
|
|
WString ToLinguisticUpper(const WString& localeName, const WString& str) const override;
|
|
|
|
vint Compare(const WString& localeName, const WString& s1, const WString& s2, Locale::Normalization normalization) const override;
|
|
vint CompareOrdinal(const WString& s1, const WString& s2) const override;
|
|
vint CompareOrdinalIgnoreCase(const WString& s1, const WString& s2) const override;
|
|
collections::Pair<vint, vint> FindFirst(const WString& localeName, const WString& text, const WString& find, Locale::Normalization normalization) const override;
|
|
collections::Pair<vint, vint> FindLast(const WString& localeName, const WString& text, const WString& find, Locale::Normalization normalization) const override;
|
|
bool StartsWith(const WString& localeName, const WString& text, const WString& find, Locale::Normalization normalization) const override;
|
|
bool EndsWith(const WString& localeName, const WString& text, const WString& find, Locale::Normalization normalization) const override;
|
|
};
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\THREADING.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_THREADING
|
|
#define VCZH_THREADING
|
|
|
|
|
|
namespace vl
|
|
{
|
|
|
|
/***********************************************************************
|
|
Kernel Mode Objects
|
|
***********************************************************************/
|
|
|
|
namespace threading_internal
|
|
{
|
|
struct WaitableData;
|
|
struct ThreadData;
|
|
struct MutexData;
|
|
struct SemaphoreData;
|
|
struct EventData;
|
|
struct CriticalSectionData;
|
|
struct ReaderWriterLockData;
|
|
struct ConditionVariableData;
|
|
}
|
|
|
|
/// <summary>Base type of all synchronization objects.</summary>
|
|
class WaitableObject : public Object
|
|
{
|
|
#if defined VCZH_MSVC
|
|
private:
|
|
threading_internal::WaitableData* waitableData;
|
|
protected:
|
|
WaitableObject();
|
|
void SetData(threading_internal::WaitableData* data);
|
|
public:
|
|
NOT_COPYABLE(WaitableObject);
|
|
|
|
/// <summary>Test if the object has already been created. Some of the synchronization objects should initialize itself after the constructor.</summary>
|
|
/// <returns>Returns true if the object has already been created.</returns>
|
|
/// <remarks>This function is only available in Windows.</remarks>
|
|
bool IsCreated();
|
|
/// <summary>Wait for this object to signal.</summary>
|
|
/// <returns>Returns true if the object is signaled. Returns false if this operation failed.</returns>
|
|
bool Wait();
|
|
/// <summary>Wait for this object to signal for a period of time.</summary>
|
|
/// <returns>Returns true if the object is signaled. Returns false if this operation failed, including time out.</returns>
|
|
/// <param name="ms">Time in milliseconds.</param>
|
|
/// <remarks>This function is only available in Windows.</remarks>
|
|
bool WaitForTime(vint ms);
|
|
|
|
/// <summary>Wait for multiple objects.</summary>
|
|
/// <returns>Returns true if all objects are signaled. Returns false if this operation failed.</returns>
|
|
/// <param name="objects">A pointer to an array to <see cref="WaitableObject"/> pointers.</param>
|
|
/// <param name="count">The number of <see cref="WaitableObject"/> objects in the array.</param>
|
|
/// <remarks>This function is only available in Windows.</remarks>
|
|
static bool WaitAll(WaitableObject** objects, vint count);
|
|
/// <summary>Wait for multiple objects for a period of time.</summary>
|
|
/// <returns>Returns true if all objects are signaled. Returns false if this operation failed, including time out.</returns>
|
|
/// <param name="objects">A pointer to an array to <see cref="WaitableObject"/> pointers.</param>
|
|
/// <param name="count">The number of <see cref="WaitableObject"/> objects in the array.</param>
|
|
/// <param name="ms">Time in milliseconds.</param>
|
|
/// <remarks>This function is only available in Windows.</remarks>
|
|
static bool WaitAllForTime(WaitableObject** objects, vint count, vint ms);
|
|
/// <summary>Wait for one of the objects.</summary>
|
|
/// <returns>Returns the index of the first signaled or abandoned object, according to the "abandoned" parameter. Returns -1 if this operation failed.</returns>
|
|
/// <param name="objects">A pointer to an array to <see cref="WaitableObject"/> pointers.</param>
|
|
/// <param name="count">The number of <see cref="WaitableObject"/> objects in the array.</param>
|
|
/// <param name="abandoned">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.</param>
|
|
/// <remarks>This function is only available in Windows.</remarks>
|
|
static vint WaitAny(WaitableObject** objects, vint count, bool* abandoned);
|
|
/// <summary>Wait for one of the objects for a period of time.</summary>
|
|
/// <returns>Returns the index of the first signaled or abandoned object, according to the "abandoned" parameter. Returns -1 if this operation failed, including time out.</returns>
|
|
/// <param name="objects">A pointer to an array to <see cref="WaitableObject"/> pointers.</param>
|
|
/// <param name="count">The number of <see cref="WaitableObject"/> objects in the array.</param>
|
|
/// <param name="ms">Time in milliseconds.</param>
|
|
/// <param name="abandoned">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.</param>
|
|
/// <remarks>This function is only available in Windows.</remarks>
|
|
static vint WaitAnyForTime(WaitableObject** objects, vint count, vint ms, bool* abandoned);
|
|
#elif defined VCZH_GCC
|
|
virtual bool Wait() = 0;
|
|
#endif
|
|
};
|
|
|
|
/// <summary>Thread. [M:vl.Thread.CreateAndStart] is the suggested way to create threads.</summary>
|
|
class Thread : public WaitableObject
|
|
{
|
|
friend void InternalThreadProc(Thread* thread);
|
|
public:
|
|
/// <summary>Thread state.</summary>
|
|
enum ThreadState
|
|
{
|
|
/// <summary>The thread has not started.</summary>
|
|
NotStarted,
|
|
/// <summary>The thread is running.</summary>
|
|
Running,
|
|
/// <summary>The thread has been stopped.</summary>
|
|
Stopped
|
|
};
|
|
|
|
typedef void(*ThreadProcedure)(Thread*, void*);
|
|
protected:
|
|
threading_internal::ThreadData* internalData;
|
|
volatile ThreadState threadState;
|
|
|
|
virtual void Run()=0;
|
|
|
|
Thread();
|
|
public:
|
|
~Thread();
|
|
|
|
/// <summary>Create a thread using a function pointer.</summary>
|
|
/// <returns>Returns the created thread.</returns>
|
|
/// <param name="procedure">The function pointer.</param>
|
|
/// <param name="argument">The argument to call the function pointer.</param>
|
|
/// <param name="deleteAfterStopped">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.</param>
|
|
static Thread* CreateAndStart(ThreadProcedure procedure, void* argument=0, bool deleteAfterStopped=true);
|
|
/// <summary>Create a thread using a function object or a lambda expression.</summary>
|
|
/// <returns>Returns the created thread.</returns>
|
|
/// <param name="procedure">The function object or the lambda expression.</param>
|
|
/// <param name="deleteAfterStopped">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.</param>
|
|
static Thread* CreateAndStart(const Func<void()>& procedure, bool deleteAfterStopped=true);
|
|
/// <summary>Pause the caller thread for a period of time.</summary>
|
|
/// <param name="ms">Time in milliseconds.</param>
|
|
static void Sleep(vint ms);
|
|
/// <summary>Get the number of logical processors.</summary>
|
|
/// <returns>The number of logical processor.</returns>
|
|
static vint GetCPUCount();
|
|
/// <summary>Get the current thread id.</summary>
|
|
/// <returns>The current thread id.</returns>
|
|
static vint GetCurrentThreadId();
|
|
|
|
/// <summary>Start the thread.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
bool Start();
|
|
#if defined VCZH_GCC
|
|
bool Wait();
|
|
#endif
|
|
/// <summary>Stop the thread.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
bool Stop();
|
|
/// <summary>Get the state of the thread.</summary>
|
|
/// <returns>The state of the thread.</returns>
|
|
ThreadState GetState();
|
|
#ifdef VCZH_MSVC
|
|
void SetCPU(vint index);
|
|
#endif
|
|
};
|
|
|
|
/// <summary>Mutex. <see cref="Create"/> or <see cref="Open"/> is required to initialize a mutex.</summary>
|
|
class Mutex : public WaitableObject
|
|
{
|
|
private:
|
|
threading_internal::MutexData* internalData;
|
|
public:
|
|
Mutex();
|
|
~Mutex();
|
|
|
|
/// <summary>Create a mutex.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="owned">Set to true to own the created mutex.</param>
|
|
/// <param name="name">Name of the mutex. If it is not empty, than it is a global named mutex. This argument is ignored in Linux.</param>
|
|
bool Create(bool owned=false, const WString& name=L"");
|
|
/// <summary>Open an existing global named mutex.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="inheritable">Set to true make the mutex visible to all all child processes. This argument is only used in Windows.</param>
|
|
/// <param name="name">Name of the mutex.</param>
|
|
bool Open(bool inheritable, const WString& name);
|
|
|
|
/// <summary>
|
|
/// Release the mutex.
|
|
/// 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.
|
|
/// </summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
bool Release();
|
|
#ifdef VCZH_GCC
|
|
bool Wait();
|
|
#endif
|
|
};
|
|
|
|
/// <summary>Semaphore. <see cref="Create"/> or <see cref="Open"/> is required to initialize a semaphore.</summary>
|
|
class Semaphore : public WaitableObject
|
|
{
|
|
private:
|
|
threading_internal::SemaphoreData* internalData;
|
|
public:
|
|
Semaphore();
|
|
~Semaphore();
|
|
|
|
/// <summary>Create a semaphore.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="initialCount">Define the counter of the semaphore.</param>
|
|
/// <param name="maxCount">Define the maximum value of the counter of the semaphore. This argument is only used in Windows.</param>
|
|
/// <param name="name">Name of the semaphore. If it is not empty, than it is a global named semaphore. This argument is ignored in Linux.</param>
|
|
bool Create(vint initialCount, vint maxCount, const WString& name=L"");
|
|
/// <summary>Open an existing global named semaphore.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="inheritable">Set to true make the semaphore visible to all all child processes. This argument is only used in Windows.</param>
|
|
/// <param name="name">Name of the semaphore.</param>
|
|
bool Open(bool inheritable, const WString& name);
|
|
|
|
/// <summary> Release the semaphore once. </summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
bool Release();
|
|
/// <summary> Release the semaphore multiple times. </summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="count">The amout to release.</param>
|
|
vint Release(vint count);
|
|
#ifdef VCZH_GCC
|
|
bool Wait();
|
|
#endif
|
|
};
|
|
|
|
/// <summary>Event. <see cref="CreateAutoUnsignal"/> or <see cref="CreateManualUnsignal"/> is required to initialize an event.</summary>
|
|
class EventObject : public WaitableObject
|
|
{
|
|
private:
|
|
threading_internal::EventData* internalData;
|
|
public:
|
|
EventObject();
|
|
~EventObject();
|
|
|
|
/// <summary>Create an auto unsignal event. Auto unsignal means, when one thread waits for the event and succeeded, the event will become unsignaled immediately.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="signaled">Set to true make the event signaled at the beginning.</param>
|
|
/// <param name="name">Name of the event. If it is not empty, than it is a global named mutex. This argument is only used in Windows.</param>
|
|
bool CreateAutoUnsignal(bool signaled, const WString& name=L"");
|
|
/// <summary>Create a manual unsignal event.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="signaled">Set to true make the event signaled at the beginning.</param>
|
|
/// <param name="name">Name of the event. If it is not empty, than it is a global named mutex. This argument is only used in Windows.</param>
|
|
bool CreateManualUnsignal(bool signaled, const WString& name=L"");
|
|
/// <summary>Open an existing global named event.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="inheritable">Set to true make the event visible to all all child processes. This argument is only used in Windows.</param>
|
|
/// <param name="name">Name of the event. This argument is only used in Windows.</param>
|
|
bool Open(bool inheritable, const WString& name);
|
|
|
|
/// <summary>Signal the event.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
bool Signal();
|
|
/// <summary>Unsignal the event.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
bool Unsignal();
|
|
#ifdef VCZH_GCC
|
|
bool Wait();
|
|
#endif
|
|
};
|
|
|
|
/***********************************************************************
|
|
Thread Pool
|
|
***********************************************************************/
|
|
|
|
/// <summary>A light-weight thread pool.</summary>
|
|
class ThreadPoolLite : public Object
|
|
{
|
|
private:
|
|
ThreadPoolLite();
|
|
~ThreadPoolLite();
|
|
public:
|
|
/// <summary>Queue a function pointer.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="proc">The function pointer.</param>
|
|
/// <param name="argument">The argument to call the function pointer.</param>
|
|
static bool Queue(void(*proc)(void*), void* argument);
|
|
/// <summary>Queue a function object.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="proc">The function object.</param>
|
|
static bool Queue(const Func<void()>& proc);
|
|
|
|
/// <summary>Queue a lambda expression.</summary>
|
|
/// <typeparam name="T">The type of the lambda expression.</typeparam>
|
|
/// <param name="proc">The lambda expression.</param>
|
|
template<typename T>
|
|
static void QueueLambda(const T& proc)
|
|
{
|
|
Queue(Func<void()>(proc));
|
|
}
|
|
|
|
#ifdef VCZH_GCC
|
|
static bool Stop(bool discardPendingTasks);
|
|
#endif
|
|
};
|
|
|
|
/***********************************************************************
|
|
Kernel Mode Objects in Process
|
|
***********************************************************************/
|
|
|
|
/// <summary>
|
|
/// Critical section.
|
|
/// The macro "CS_LOCK" is recommended instead of calling [M:vl.CriticalSection.Enter] and [M:vl.CriticalSection.Leave] like this:
|
|
/// <program><code><![CDATA[
|
|
/// CS_LOCK(yourCriticalSection)
|
|
/// {
|
|
/// // do something
|
|
/// }
|
|
/// ]]></code></program>
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// In Windows, enter a owned critical section will not result in dead lock.
|
|
/// In Linux and macOS, it works like a mutex.
|
|
/// </remarks>
|
|
class CriticalSection : public Object
|
|
{
|
|
private:
|
|
friend class ConditionVariable;
|
|
threading_internal::CriticalSectionData* internalData;
|
|
public:
|
|
NOT_COPYABLE(CriticalSection);
|
|
/// <summary>Create a critical section.</summary>
|
|
CriticalSection();
|
|
~CriticalSection();
|
|
|
|
/// <summary>Try enter a critical section. This function will return immediately.</summary>
|
|
/// <returns>Returns true if the current thread owned the critical section.</returns>
|
|
bool TryEnter();
|
|
/// <summary>Enter a critical section.</summary>
|
|
void Enter();
|
|
/// <summary>Leave a critical section.</summary>
|
|
void Leave();
|
|
|
|
public:
|
|
class Scope : public Object
|
|
{
|
|
private:
|
|
CriticalSection* criticalSection;
|
|
public:
|
|
NOT_COPYABLE(Scope);
|
|
Scope(CriticalSection& _criticalSection);
|
|
~Scope();
|
|
};
|
|
};
|
|
|
|
/// <summary>
|
|
/// Reader writer lock.
|
|
/// 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:
|
|
/// <program><code><![CDATA[
|
|
/// READER_LOCK(yourLock)
|
|
/// {
|
|
/// // do something
|
|
/// }
|
|
/// ]]></code></program>
|
|
/// or
|
|
/// <program><code><![CDATA[
|
|
/// WRITER_LOCK(yourLock)
|
|
/// {
|
|
/// // do something
|
|
/// }
|
|
/// ]]></code></program>
|
|
/// </summary>
|
|
class ReaderWriterLock : public Object
|
|
{
|
|
private:
|
|
friend class ConditionVariable;
|
|
threading_internal::ReaderWriterLockData* internalData;
|
|
public:
|
|
NOT_COPYABLE(ReaderWriterLock);
|
|
/// <summary>Create a reader writer lock.</summary>
|
|
ReaderWriterLock();
|
|
~ReaderWriterLock();
|
|
|
|
/// <summary>Try acquire a reader lock. This function will return immediately.</summary>
|
|
/// <returns>Returns true if the current thread acquired the reader lock.</returns>
|
|
bool TryEnterReader();
|
|
/// <summary>Acquire a reader lock.</summary>
|
|
void EnterReader();
|
|
/// <summary>Release a reader lock.</summary>
|
|
void LeaveReader();
|
|
/// <summary>Try acquire a writer lock. This function will return immediately.</summary>
|
|
/// <returns>Returns true if the current thread acquired the writer lock.</returns>
|
|
bool TryEnterWriter();
|
|
/// <summary>Acquire a writer lock.</summary>
|
|
void EnterWriter();
|
|
/// <summary>Release a writer lock.</summary>
|
|
void LeaveWriter();
|
|
public:
|
|
class ReaderScope : public Object
|
|
{
|
|
private:
|
|
ReaderWriterLock* lock;
|
|
public:
|
|
NOT_COPYABLE(ReaderScope);
|
|
ReaderScope(ReaderWriterLock& _lock);
|
|
~ReaderScope();
|
|
};
|
|
|
|
class WriterScope : public Object
|
|
{
|
|
private:
|
|
ReaderWriterLock* lock;
|
|
public:
|
|
NOT_COPYABLE(WriterScope);
|
|
WriterScope(ReaderWriterLock& _lock);
|
|
~WriterScope();
|
|
};
|
|
};
|
|
|
|
/// <summary>Conditional variable.</summary>
|
|
class ConditionVariable : public Object
|
|
{
|
|
private:
|
|
threading_internal::ConditionVariableData* internalData;
|
|
public:
|
|
NOT_COPYABLE(ConditionVariable);
|
|
/// <summary>Create a conditional variable.</summary>
|
|
ConditionVariable();
|
|
~ConditionVariable();
|
|
|
|
/// <summary>Bind a conditional variable with a owned critical section and release it. When the function returns, the condition variable is activated, and the current thread owned the critical section again.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="cs">The critical section.</param>
|
|
bool SleepWith(CriticalSection& cs);
|
|
#ifdef VCZH_MSVC
|
|
/// <summary>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.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="cs">The critical section.</param>
|
|
/// <param name="ms">Time in milliseconds.</param>
|
|
/// <remarks>This function is only available in Windows.</remarks>
|
|
bool SleepWithForTime(CriticalSection& cs, vint ms);
|
|
/// <summary>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.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="lock">The reader lock.</param>
|
|
/// <remarks>This function is only available in Windows.</remarks>
|
|
bool SleepWithReader(ReaderWriterLock& lock);
|
|
/// <summary>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.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="lock">The reader lock.</param>
|
|
/// <param name="ms">Time in milliseconds.</param>
|
|
/// <remarks>This function is only available in Windows.</remarks>
|
|
bool SleepWithReaderForTime(ReaderWriterLock& lock, vint ms);
|
|
/// <summary>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.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="lock">The writer lock.</param>
|
|
/// <remarks>This function is only available in Windows.</remarks>
|
|
bool SleepWithWriter(ReaderWriterLock& lock);
|
|
/// <summary>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.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="lock">The writer lock.</param>
|
|
/// <param name="ms">Time in milliseconds.</param>
|
|
/// <remarks>This function is only available in Windows.</remarks>
|
|
bool SleepWithWriterForTime(ReaderWriterLock& lock, vint ms);
|
|
#endif
|
|
/// <summary>Wake one thread that pending on this condition variable.</summary>
|
|
void WakeOnePending();
|
|
/// <summary>Wake all thread that pending on this condition variable.</summary>
|
|
void WakeAllPendings();
|
|
};
|
|
|
|
/***********************************************************************
|
|
User Mode Objects
|
|
***********************************************************************/
|
|
|
|
/// <summary>
|
|
/// 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:
|
|
/// <program><code><![CDATA[
|
|
/// SPIN_LOCK(yourLock)
|
|
/// {
|
|
/// // do something
|
|
/// }
|
|
/// ]]></code></program>
|
|
/// </summary>
|
|
class SpinLock : public Object
|
|
{
|
|
protected:
|
|
atomic_vint token = 0;
|
|
public:
|
|
NOT_COPYABLE(SpinLock);
|
|
/// <summary>Create a spin lock.</summary>
|
|
SpinLock() = default;
|
|
~SpinLock() = default;
|
|
|
|
/// <summary>Try enter a spin lock. This function will return immediately.</summary>
|
|
/// <returns>Returns true if the current thread owned the spin lock.</returns>
|
|
bool TryEnter();
|
|
/// <summary>Enter a spin lock.</summary>
|
|
void Enter();
|
|
/// <summary>Leave a spin lock.</summary>
|
|
void Leave();
|
|
|
|
public:
|
|
class Scope : public Object
|
|
{
|
|
private:
|
|
SpinLock* spinLock;
|
|
public:
|
|
NOT_COPYABLE(Scope);
|
|
Scope(SpinLock& _spinLock);
|
|
~Scope();
|
|
};
|
|
};
|
|
|
|
#define SPIN_LOCK(LOCK) SCOPE_VARIABLE(const SpinLock::Scope&, scope, LOCK)
|
|
#define CS_LOCK(LOCK) SCOPE_VARIABLE(const CriticalSection::Scope&, scope, LOCK)
|
|
#define READER_LOCK(LOCK) SCOPE_VARIABLE(const ReaderWriterLock::ReaderScope&, scope, LOCK)
|
|
#define WRITER_LOCK(LOCK) SCOPE_VARIABLE(const ReaderWriterLock::WriterScope&, scope, LOCK)
|
|
|
|
/***********************************************************************
|
|
Thread Local Storage
|
|
***********************************************************************/
|
|
|
|
/// <summary>Thread local storage operations.</summary>
|
|
/// <remarks>
|
|
/// This class is designed to define global variables.
|
|
/// Dynamically allocation will result in undefined behavior.
|
|
/// </remarks>
|
|
class ThreadLocalStorage : public Object
|
|
{
|
|
typedef void(*Destructor)(void*);
|
|
protected:
|
|
vuint64_t key;
|
|
Destructor destructor;
|
|
volatile bool disposed = false;
|
|
|
|
static void PushStorage(ThreadLocalStorage* storage);
|
|
public:
|
|
NOT_COPYABLE(ThreadLocalStorage);
|
|
ThreadLocalStorage(Destructor _destructor);
|
|
~ThreadLocalStorage();
|
|
|
|
void* Get();
|
|
void Set(void* data);
|
|
void Clear();
|
|
void Dispose();
|
|
|
|
/// <summary>Fix all storage creation.</summary>
|
|
static void FixStorages();
|
|
/// <summary>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.</summary>
|
|
static void ClearStorages();
|
|
/// <summary>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.</summary>
|
|
static void DisposeStorages();
|
|
};
|
|
|
|
/// <summary>Thread local variable. Different threads can store different values to and obtain differnt values from a thread local variable.</summary>
|
|
/// <typeparam name="T">Type of the storage.</typeparam>
|
|
/// <remarks>
|
|
/// This class is designed to define global variables.
|
|
/// Dynamically allocation will result in undefined behavior.
|
|
/// </remarks>
|
|
template<typename T>
|
|
class ThreadVariable : public Object
|
|
{
|
|
protected:
|
|
ThreadLocalStorage storage;
|
|
|
|
static void Destructor(void* data)
|
|
{
|
|
if (data)
|
|
{
|
|
delete (T*)data;
|
|
}
|
|
}
|
|
public:
|
|
NOT_COPYABLE(ThreadVariable);
|
|
|
|
/// <summary>Create a thread local variable.</summary>
|
|
ThreadVariable()
|
|
:storage(&Destructor)
|
|
{
|
|
}
|
|
|
|
~ThreadVariable()
|
|
{
|
|
}
|
|
|
|
/// <summary>Test if the storage has data.</summary>
|
|
/// <returns>Returns true if the storage has data.</returns>
|
|
bool HasData()
|
|
{
|
|
return storage.Get() != nullptr;
|
|
}
|
|
|
|
/// <summary>Remove the data from this storage.</summary>
|
|
void Clear()
|
|
{
|
|
storage.Clear();
|
|
}
|
|
|
|
/// <summary>Get the stored data.</summary>
|
|
/// <returns>The stored ata.</returns>
|
|
T& Get()
|
|
{
|
|
return *(T*)storage.Get();
|
|
}
|
|
|
|
/// <summary>Set data to this storage.</summary>
|
|
/// <param name="value">The data to set.</param>
|
|
void Set(const T& value)
|
|
{
|
|
storage.Clear();
|
|
storage.Set(new T(value));
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
class ThreadVariable<T*> : public Object
|
|
{
|
|
protected:
|
|
ThreadLocalStorage storage;
|
|
|
|
public:
|
|
NOT_COPYABLE(ThreadVariable);
|
|
|
|
ThreadVariable()
|
|
:storage(nullptr)
|
|
{
|
|
}
|
|
|
|
~ThreadVariable()
|
|
{
|
|
}
|
|
|
|
bool HasData()
|
|
{
|
|
return storage.Get() != nullptr;
|
|
}
|
|
|
|
void Clear()
|
|
{
|
|
storage.Set(nullptr);
|
|
}
|
|
|
|
T* Get()
|
|
{
|
|
return (T*)storage.Get();
|
|
}
|
|
|
|
void Set(T* value)
|
|
{
|
|
storage.Set((void*)value);
|
|
}
|
|
};
|
|
|
|
/***********************************************************************
|
|
RepeatingTaskExecutor
|
|
***********************************************************************/
|
|
|
|
/// <summary>
|
|
/// Queued task executor. It is different from a thread because:
|
|
/// <ul>
|
|
/// <li>Task execution is single threaded.</li>
|
|
/// <li>If you queue a task, it will override all unexecuted queued tasks.</li>
|
|
/// </ul>
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of the argument to run a task.</typeparam>
|
|
template<typename T>
|
|
class RepeatingTaskExecutor : public Object
|
|
{
|
|
private:
|
|
SpinLock inputLock;
|
|
T inputData;
|
|
volatile bool inputDataAvailable;
|
|
SpinLock executingEvent;
|
|
volatile bool executing;
|
|
|
|
void ExecutingProcInternal()
|
|
{
|
|
while(true)
|
|
{
|
|
bool currentInputDataAvailable;
|
|
T currentInputData;
|
|
SPIN_LOCK(inputLock)
|
|
{
|
|
currentInputData=inputData;
|
|
inputData=T();
|
|
currentInputDataAvailable=inputDataAvailable;
|
|
inputDataAvailable=false;
|
|
if(!currentInputDataAvailable)
|
|
{
|
|
executing=false;
|
|
goto FINISH_EXECUTING;
|
|
}
|
|
}
|
|
Execute(currentInputData);
|
|
}
|
|
FINISH_EXECUTING:
|
|
executingEvent.Leave();
|
|
}
|
|
|
|
static void ExecutingProc(void* argument)
|
|
{
|
|
((RepeatingTaskExecutor<T>*)argument)->ExecutingProcInternal();
|
|
}
|
|
|
|
protected:
|
|
/// <summary>This function is called when it is ready to execute a task. Task execution is single threaded. All task code should be put inside the function.</summary>
|
|
/// <param name="input">The argument to run a task.</param>
|
|
virtual void Execute(const T& input)=0;
|
|
|
|
public:
|
|
/// <summary>Create a task executor.</summary>
|
|
RepeatingTaskExecutor()
|
|
:inputDataAvailable(false)
|
|
,executing(false)
|
|
{
|
|
}
|
|
|
|
~RepeatingTaskExecutor()
|
|
{
|
|
EnsureTaskFinished();
|
|
}
|
|
|
|
/// <summary>Wait for all tasks to finish.</summary>
|
|
void EnsureTaskFinished()
|
|
{
|
|
executingEvent.Enter();
|
|
executingEvent.Leave();
|
|
}
|
|
|
|
/// <summary>Queue a task.</summary>
|
|
/// <param name="input">The argument to run a task.</param>
|
|
/// <remarks>
|
|
/// <p>
|
|
/// 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.
|
|
/// </p>
|
|
/// </remarks>
|
|
void SubmitTask(const T& input)
|
|
{
|
|
SPIN_LOCK(inputLock)
|
|
{
|
|
inputData=input;
|
|
inputDataAvailable=true;
|
|
}
|
|
if(!executing)
|
|
{
|
|
executing=true;
|
|
executingEvent.Enter();
|
|
ThreadPoolLite::Queue(&ExecutingProc, this);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
#endif
|
|
|
|
|
|
/***********************************************************************
|
|
.\STREAM\INTERFACES.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_STREAM_INTERFACES
|
|
#define VCZH_STREAM_INTERFACES
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace stream
|
|
{
|
|
/// <summary>
|
|
/// <p>
|
|
/// Interface for streams.
|
|
/// </p>
|
|
/// <p>
|
|
/// Please notice that, even if you get a stream object, if [M:vl.stream.IStream.IsAvailable] returns false, all other methods cannot be used.
|
|
/// </p>
|
|
/// <p>
|
|
/// 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:
|
|
/// </p>
|
|
/// <p>
|
|
/// <ul>
|
|
/// <li><b>Readable</b>: A stream is readable if [M:vl.stream.IStream.CanRead] returns true.</li>
|
|
/// <li><b>Peekable</b>: A stream is peekable if [M:vl.stream.IStream.CanPeek] returns true.</li>
|
|
/// <li><b>Writable</b>: A stream is writable if [M:vl.stream.IStream.CanWrite] returns true.</li>
|
|
/// <li><b>Seekable</b>: A stream is readable if [M:vl.stream.IStream.CanSeek] returns true.</li>
|
|
/// <li><b>Finite</b>: A stream is finite if [M:vl.stream.IStream.IsLimited] returns true.</li>
|
|
/// </ul>
|
|
/// </p>
|
|
/// </summary>
|
|
class IStream : public virtual Interface
|
|
{
|
|
public:
|
|
/// <summary>Test if the stream is <b>readable</b>.</summary>
|
|
/// <returns>Returns true if the stream is <b>readable</b>.</returns>
|
|
virtual bool CanRead()const=0;
|
|
/// <summary>Test if the stream is <b>writable</b>.</summary>
|
|
/// <returns>Returns true if the stream is <b>writable</b>.</returns>
|
|
virtual bool CanWrite()const=0;
|
|
/// <summary>Test if the stream is <b>seekable</b>.</summary>
|
|
/// <returns>Returns true if the stream is <b>seekable</b>.</returns>
|
|
virtual bool CanSeek()const=0;
|
|
/// <summary>Test if the stream is <b>peekable</b>.</summary>
|
|
/// <returns>Returns true if the stream is <b>peekable</b>.</returns>
|
|
virtual bool CanPeek()const=0;
|
|
/// <summary>Test if the content of the stream is <b>finite</b>. A writable stream can also be limited, it means that you can only write limited content to the stream.</summary>
|
|
/// <returns>Returns true if the content of the stream is <b>finite</b>.</returns>
|
|
virtual bool IsLimited()const=0;
|
|
/// <summary>Test if the stream is <b>available</b>. For example, if you create a readable [T:vl.stream.FileStream] giving a wrong file name, it will be unavailable.</summary>
|
|
/// <returns>Returns true if the stream is <b>available</b>.</returns>
|
|
virtual bool IsAvailable()const=0;
|
|
/// <summary>Close the stream, making the stream <b>unavailable</b>.</summary>
|
|
virtual void Close()=0;
|
|
/// <summary>Get the current position in the stream.</summary>
|
|
/// <returns>The position in the stream. Returns -1 if the stream is <b>unavailable</b>.</returns>
|
|
virtual pos_t Position()const=0;
|
|
/// <summary>Get the size of the content in this stream.</summary>
|
|
/// <returns>The size of the content in this stream. Returns -1 if the size is <b>unsizable</b> or <b>unavailable</b>.</returns>
|
|
virtual pos_t Size()const=0;
|
|
/// <summary>Step forward or backward from the current position. It will crash if the stream is <b>unseekable</b> or <b>unavailable</b>.</summary>
|
|
/// <param name="_size">The length to step forward if it is a positive number. The length to step backward if it is a negative number</param>
|
|
virtual void Seek(pos_t _size)=0;
|
|
/// <summary>Step forward from the beginning. It will crash if the stream is <b>unseekable</b> or <b>unavailable</b>.</summary>
|
|
/// <param name="_size">The length to step forward.</param>
|
|
virtual void SeekFromBegin(pos_t _size)=0;
|
|
/// <summary>Step backward from the end. It will crash if the stream is <b>unseekable</b> or <b>unavailable</b>.</summary>
|
|
/// <param name="_size">The length to step backward.</param>
|
|
virtual void SeekFromEnd(pos_t _size)=0;
|
|
/// <summary>Read from the current position and step forward. It will crash if the stream is <b>unreadable</b> or <b>unavailable</b>.</summary>
|
|
/// <returns>Returns the actual size of the content that has read. Returns 0 if a stream has no more data to read.</returns>
|
|
/// <param name="_buffer">A buffer to store the content.</param>
|
|
/// <param name="_size">The size of the content that is expected to read.</param>
|
|
virtual vint Read(void* _buffer, vint _size)=0;
|
|
/// <summary>Write to the current position and step forward. It will crash if the stream is <b>unwritable</b> or <b>unavailable</b>.</summary>
|
|
/// <returns>Returns the actual size of the content that has written. Returns 0 if a stream has not enough space to write.</returns>
|
|
/// <param name="_buffer">A buffer storing the content to write.</param>
|
|
/// <param name="_size">The size of the content that is expected to write.</param>
|
|
virtual vint Write(void* _buffer, vint _size)=0;
|
|
/// <summary>Read from the current position without stepping forward. It will crash if the stream is <b>unpeekable</b> or <b>unavailable</b>.</summary>
|
|
/// <returns>Returns the actual size of the content that is read. Returns 0 if a stream has no more data to read.</returns>
|
|
/// <param name="_buffer">A buffer to store the content.</param>
|
|
/// <param name="_size">The size of the content that is expected to read.</param>
|
|
virtual vint Peek(void* _buffer, vint _size)=0;
|
|
};
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\ENCODING\ENCODING.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_STREAM_ENCODING_ENCODING
|
|
#define VCZH_STREAM_ENCODING_ENCODING
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace stream
|
|
{
|
|
/***********************************************************************
|
|
IEncoder and IDecoder
|
|
***********************************************************************/
|
|
|
|
/// <summary>Encoder interface. This interface defines a writable transformation from one stream to another stream. You can create a [T:vl.stream.EncoderStream] after you have an encoder.</summary>
|
|
class IEncoder : public Interface
|
|
{
|
|
public:
|
|
/// <summary>Set a target <b>writable</b> stream to receive data. <see cref="Write"/> transforms the content and write to this tream.</summary>
|
|
/// <param name="_stream">The target <b>writable</b> stream.</param>
|
|
virtual void Setup(IStream* _stream)=0;
|
|
/// <summary>Stop the transformation, ensuring all content is written to the target stream.</summary>
|
|
virtual void Close()=0;
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// Returns the actual size of the content that has written <b>before</b> transforming.
|
|
/// A successful write operation may only cache the data without actually write anything to the target stream.
|
|
/// </returns>
|
|
/// <param name="_buffer">A buffer storing the content to transform.</param>
|
|
/// <param name="_size">The expected size of the content in bytes in "_buffer" to use.</param>
|
|
virtual vint Write(void* _buffer, vint _size)=0;
|
|
};
|
|
|
|
/// <summary>Decoder interface. This interface defines a readable transformation from one stream to another stream. You can create a [T:vl.stream.DecoderStream] after you have an decoder.</summary>
|
|
class IDecoder : public Interface
|
|
{
|
|
public:
|
|
/// <summary>
|
|
/// Set a target <b>readable</b> stream.
|
|
/// <see cref="Read"/> reads from this tream and transform the content.
|
|
/// </summary>
|
|
/// <param name="_stream">The target <b>readable</b> stream.</param>
|
|
virtual void Setup(IStream* _stream)=0;
|
|
/// <summary>Stop the transformation.</summary>
|
|
virtual void Close()=0;
|
|
/// <summary>Read from the target stream and transform the content.</summary>
|
|
/// <returns>Returns the actual size of the content has read after transforming.</returns>
|
|
/// <param name="_buffer">A buffer to store the content.</param>
|
|
/// <param name="_size">The expected size of the content in bytes in "_buffer" to receive.</param>
|
|
virtual vint Read(void* _buffer, vint _size)=0;
|
|
};
|
|
|
|
/***********************************************************************
|
|
EncoderBase and DecoderBase
|
|
***********************************************************************/
|
|
|
|
/// <summary>Basic implementation of IEncoder.</summary>
|
|
class EncoderBase : public Object, public IEncoder
|
|
{
|
|
protected:
|
|
IStream* stream = nullptr;
|
|
|
|
public:
|
|
|
|
void Setup(IStream* _stream) override;
|
|
void Close() override;
|
|
};
|
|
|
|
/// <summary>Basic implementation of IDecoder.</summary>
|
|
class DecoderBase : public Object, public IDecoder
|
|
{
|
|
protected:
|
|
IStream* stream = nullptr;
|
|
|
|
public:
|
|
|
|
void Setup(IStream* _stream) override;
|
|
void Close() override;
|
|
};
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\ENCODING\BASE64ENCODING.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_STREAM_ENCODING_BASE64ENCODING
|
|
#define VCZH_STREAM_ENCODING_BASE64ENCODING
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace stream
|
|
{
|
|
constexpr const vint Base64CycleBytes = 3;
|
|
constexpr const vint Base64CycleChars = 4;
|
|
|
|
/***********************************************************************
|
|
Utf8Base64Encoder
|
|
***********************************************************************/
|
|
|
|
class Utf8Base64Encoder : public EncoderBase
|
|
{
|
|
protected:
|
|
uint8_t cache[Base64CycleBytes];
|
|
vint cacheSize = 0;
|
|
|
|
void WriteBytesToCharArray(uint8_t* fromBytes, char8_t(&toChars)[Base64CycleChars], vint bytes);
|
|
bool WriteCycle(uint8_t*& reading, vint& _size);
|
|
bool WriteCache(uint8_t*& reading, vint& _size);
|
|
public:
|
|
vint Write(void* _buffer, vint _size) override;
|
|
void Close() override;
|
|
};
|
|
|
|
/***********************************************************************
|
|
Utf8Base64Decoder
|
|
***********************************************************************/
|
|
|
|
class Utf8Base64Decoder : public DecoderBase
|
|
{
|
|
protected:
|
|
uint8_t cache[Base64CycleBytes];
|
|
vint cacheSize = 0;
|
|
|
|
vint ReadBytesFromCharArray(char8_t(&fromChars)[Base64CycleChars], uint8_t* toBytes);
|
|
vint ReadCycle(uint8_t*& writing, vint& _size);
|
|
void ReadCache(uint8_t*& writing, vint& _size);
|
|
public:
|
|
vint Read(void* _buffer, vint _size) override;
|
|
};
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/***********************************************************************
|
|
.\ENCODING\CHARFORMAT\BOMENCODING.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_STREAM_ENCODING_CHARFORMAT_BOMENCODING
|
|
#define VCZH_STREAM_ENCODING_CHARFORMAT_BOMENCODING
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace stream
|
|
{
|
|
/***********************************************************************
|
|
Bom
|
|
***********************************************************************/
|
|
|
|
/// <summary>Encoder to write text in a specified encoding. A BOM will be added at the beginning.</summary>
|
|
class BomEncoder : public Object, public IEncoder
|
|
{
|
|
public:
|
|
/// <summary>Text encoding.</summary>
|
|
enum Encoding
|
|
{
|
|
/// <summary>Multi-bytes character string.</summary>
|
|
Mbcs,
|
|
/// <summary>UTF-8. EF, BB, BF will be written before writing any text.</summary>
|
|
Utf8,
|
|
/// <summary>UTF-16. FF FE will be written before writing any text.</summary>
|
|
Utf16,
|
|
/// <summary>Big endian UTF-16. FE FF, BF will be written before writing any text.</summary>
|
|
Utf16BE
|
|
};
|
|
protected:
|
|
Encoding encoding;
|
|
IEncoder* encoder;
|
|
public:
|
|
/// <summary>Create an encoder with a specified encoding.</summary>
|
|
/// <param name="_encoding">The specified encoding.</param>
|
|
BomEncoder(Encoding _encoding);
|
|
~BomEncoder();
|
|
|
|
void Setup(IStream* _stream);
|
|
void Close();
|
|
vint Write(void* _buffer, vint _size);
|
|
};
|
|
|
|
/// <summary>Decoder to read text. This decoder depends on BOM at the beginning to decide the format of the input.</summary>
|
|
class BomDecoder : public Object, public IDecoder
|
|
{
|
|
private:
|
|
class BomStream : public Object, public IStream
|
|
{
|
|
protected:
|
|
IStream* stream;
|
|
char bom[3];
|
|
vint bomLength;
|
|
vint bomPosition;
|
|
public:
|
|
BomStream(IStream* _stream, char* _bom, vint _bomLength);
|
|
|
|
bool CanRead()const;
|
|
bool CanWrite()const;
|
|
bool CanSeek()const;
|
|
bool CanPeek()const;
|
|
bool IsLimited()const;
|
|
bool IsAvailable()const;
|
|
void Close();
|
|
pos_t Position()const;
|
|
pos_t Size()const;
|
|
void Seek(pos_t _size);
|
|
void SeekFromBegin(pos_t _size);
|
|
void SeekFromEnd(pos_t _size);
|
|
vint Read(void* _buffer, vint _size);
|
|
vint Write(void* _buffer, vint _size);
|
|
vint Peek(void* _buffer, vint _size);
|
|
};
|
|
protected:
|
|
IDecoder* decoder;
|
|
IStream* stream;
|
|
|
|
public:
|
|
/// <summary>Create an decoder, BOM will be consumed before reading any text.</summary>
|
|
BomDecoder();
|
|
~BomDecoder();
|
|
|
|
void Setup(IStream* _stream);
|
|
void Close();
|
|
vint Read(void* _buffer, vint _size);
|
|
};
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/***********************************************************************
|
|
.\ENCODING\CHARFORMAT\MBCSENCODING.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_STREAM_ENCODING_CHARFORMAT_MBCSENCODING
|
|
#define VCZH_STREAM_ENCODING_CHARFORMAT_MBCSENCODING
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace stream
|
|
{
|
|
/***********************************************************************
|
|
MbcsEncoder
|
|
***********************************************************************/
|
|
|
|
/// <summary>Encoder to write text in the local code page.</summary>
|
|
class MbcsEncoder : public EncoderBase
|
|
{
|
|
protected:
|
|
vuint8_t cacheBuffer[sizeof(char32_t)];
|
|
vint cacheSize = 0;
|
|
|
|
vint WriteString(wchar_t* _buffer, vint chars);
|
|
public:
|
|
|
|
vint Write(void* _buffer, vint _size) override;
|
|
};
|
|
|
|
/***********************************************************************
|
|
MbcsDecoder
|
|
***********************************************************************/
|
|
|
|
/// <summary>Decoder to read text in the local code page.</summary>
|
|
class MbcsDecoder : public DecoderBase
|
|
{
|
|
protected:
|
|
vuint8_t cacheBuffer[sizeof(wchar_t)];
|
|
vint cacheSize = 0;
|
|
|
|
vint ReadString(wchar_t* _buffer, vint chars);
|
|
public:
|
|
|
|
vint Read(void* _buffer, vint _size) override;
|
|
};
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/***********************************************************************
|
|
.\ENCODING\CHARFORMAT\UTFENCODING.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_STREAM_ENCODING_CHARFORMAT_UTFENCODING
|
|
#define VCZH_STREAM_ENCODING_CHARFORMAT_UTFENCODING
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace stream
|
|
{
|
|
|
|
/***********************************************************************
|
|
UtfStreamConsumer<T>
|
|
***********************************************************************/
|
|
|
|
template<typename T>
|
|
class UtfStreamConsumer : public Object
|
|
{
|
|
protected:
|
|
IStream* stream = nullptr;
|
|
|
|
T Consume()
|
|
{
|
|
T c;
|
|
vint size = stream->Read(&c, sizeof(c));
|
|
if (size != sizeof(c)) return 0;
|
|
return c;
|
|
}
|
|
public:
|
|
void Setup(IStream* _stream)
|
|
{
|
|
stream = _stream;
|
|
}
|
|
|
|
bool HasIllegalChar() const
|
|
{
|
|
return false;
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
class UtfStreamConsumerApiRedirection : public Object
|
|
{
|
|
private:
|
|
T& internalConsumer;
|
|
|
|
public:
|
|
UtfStreamConsumerApiRedirection(T& _internalConsumer)
|
|
: internalConsumer(_internalConsumer)
|
|
{
|
|
}
|
|
|
|
void Setup(IStream* _stream)
|
|
{
|
|
internalConsumer.Setup(_stream);
|
|
}
|
|
|
|
encoding::UtfCharCluster SourceCluster() const
|
|
{
|
|
return internalConsumer.SourceCluster();
|
|
}
|
|
};
|
|
|
|
/***********************************************************************
|
|
UtfStreamToStreamReader<TFrom, TTo>
|
|
***********************************************************************/
|
|
|
|
template<typename TFrom, typename TTo>
|
|
using UtfStreamToStreamReader = encoding::UtfToUtfReaderBase<TFrom, TTo, UtfStreamConsumer<TFrom>, UtfStreamConsumerApiRedirection>;
|
|
|
|
/***********************************************************************
|
|
Unicode General
|
|
***********************************************************************/
|
|
|
|
template<typename T>
|
|
struct MaxPossibleCodePoints
|
|
{
|
|
static const vint Value = encoding::UtfConversion<T>::BufferLength;
|
|
};
|
|
|
|
template<>
|
|
struct MaxPossibleCodePoints<char32_t>
|
|
{
|
|
static const vint Value = 1;
|
|
};
|
|
|
|
template<typename TNative, typename TExpect>
|
|
class UtfGeneralEncoder : public EncoderBase
|
|
{
|
|
using TStringRangeReader = encoding::UtfStringRangeToStringRangeReader<TExpect, TNative>;
|
|
protected:
|
|
vuint8_t cacheBuffer[sizeof(TExpect) * MaxPossibleCodePoints<TExpect>::Value];
|
|
vint cacheSize = 0;
|
|
|
|
public:
|
|
|
|
vint Write(void* _buffer, vint _size) override;
|
|
};
|
|
|
|
template<typename TNative, typename TExpect>
|
|
class UtfGeneralDecoder : public DecoderBase
|
|
{
|
|
using TStreamReader = UtfStreamToStreamReader<TNative, TExpect>;
|
|
protected:
|
|
vuint8_t cacheBuffer[sizeof(TExpect)];
|
|
vint cacheSize = 0;
|
|
TStreamReader reader;
|
|
|
|
public:
|
|
|
|
void Setup(IStream* _stream) override;
|
|
vint Read(void* _buffer, vint _size) override;
|
|
};
|
|
|
|
/***********************************************************************
|
|
Unicode General (without conversion)
|
|
***********************************************************************/
|
|
|
|
template<typename T>
|
|
class UtfGeneralEncoder<T, T> : public EncoderBase
|
|
{
|
|
public:
|
|
vint Write(void* _buffer, vint _size) override;
|
|
};
|
|
|
|
template<typename T>
|
|
class UtfGeneralDecoder<T, T> : public DecoderBase
|
|
{
|
|
public:
|
|
vint Read(void* _buffer, vint _size) override;
|
|
};
|
|
|
|
#if defined VCZH_WCHAR_UTF16
|
|
|
|
template<>
|
|
class UtfGeneralEncoder<char16_t, wchar_t> : public UtfGeneralEncoder<wchar_t, wchar_t> {};
|
|
|
|
template<>
|
|
class UtfGeneralEncoder<wchar_t, char16_t> : public UtfGeneralEncoder<wchar_t, wchar_t> {};
|
|
|
|
#elif defined VCZH_WCHAR_UTF32
|
|
|
|
template<>
|
|
class UtfGeneralEncoder<char32_t, wchar_t> : public UtfGeneralEncoder<wchar_t, wchar_t> {};
|
|
|
|
template<>
|
|
class UtfGeneralEncoder<wchar_t, char32_t> : public UtfGeneralEncoder<wchar_t, wchar_t> {};
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
Unicode General (extern templates)
|
|
***********************************************************************/
|
|
|
|
extern template class UtfGeneralEncoder<wchar_t, wchar_t>;
|
|
extern template class UtfGeneralEncoder<wchar_t, char8_t>;
|
|
extern template class UtfGeneralEncoder<wchar_t, char16_t>;
|
|
extern template class UtfGeneralEncoder<wchar_t, char16be_t>;
|
|
extern template class UtfGeneralEncoder<wchar_t, char32_t>;
|
|
|
|
extern template class UtfGeneralEncoder<char8_t, wchar_t>;
|
|
extern template class UtfGeneralEncoder<char8_t, char8_t>;
|
|
extern template class UtfGeneralEncoder<char8_t, char16_t>;
|
|
extern template class UtfGeneralEncoder<char8_t, char16be_t>;
|
|
extern template class UtfGeneralEncoder<char8_t, char32_t>;
|
|
|
|
extern template class UtfGeneralEncoder<char16_t, wchar_t>;
|
|
extern template class UtfGeneralEncoder<char16_t, char8_t>;
|
|
extern template class UtfGeneralEncoder<char16_t, char16_t>;
|
|
extern template class UtfGeneralEncoder<char16_t, char16be_t>;
|
|
extern template class UtfGeneralEncoder<char16_t, char32_t>;
|
|
|
|
extern template class UtfGeneralEncoder<char16be_t, wchar_t>;
|
|
extern template class UtfGeneralEncoder<char16be_t, char8_t>;
|
|
extern template class UtfGeneralEncoder<char16be_t, char16_t>;
|
|
extern template class UtfGeneralEncoder<char16be_t, char16be_t>;
|
|
extern template class UtfGeneralEncoder<char16be_t, char32_t>;
|
|
|
|
extern template class UtfGeneralEncoder<char32_t, wchar_t>;
|
|
extern template class UtfGeneralEncoder<char32_t, char8_t>;
|
|
extern template class UtfGeneralEncoder<char32_t, char16_t>;
|
|
extern template class UtfGeneralEncoder<char32_t, char16be_t>;
|
|
extern template class UtfGeneralEncoder<char32_t, char32_t>;
|
|
|
|
extern template class UtfGeneralDecoder<wchar_t, wchar_t>;
|
|
extern template class UtfGeneralDecoder<wchar_t, char8_t>;
|
|
extern template class UtfGeneralDecoder<wchar_t, char16_t>;
|
|
extern template class UtfGeneralDecoder<wchar_t, char16be_t>;
|
|
extern template class UtfGeneralDecoder<wchar_t, char32_t>;
|
|
|
|
extern template class UtfGeneralDecoder<char8_t, wchar_t>;
|
|
extern template class UtfGeneralDecoder<char8_t, char8_t>;
|
|
extern template class UtfGeneralDecoder<char8_t, char16_t>;
|
|
extern template class UtfGeneralDecoder<char8_t, char16be_t>;
|
|
extern template class UtfGeneralDecoder<char8_t, char32_t>;
|
|
|
|
extern template class UtfGeneralDecoder<char16_t, wchar_t>;
|
|
extern template class UtfGeneralDecoder<char16_t, char8_t>;
|
|
extern template class UtfGeneralDecoder<char16_t, char16_t>;
|
|
extern template class UtfGeneralDecoder<char16_t, char16be_t>;
|
|
extern template class UtfGeneralDecoder<char16_t, char32_t>;
|
|
|
|
extern template class UtfGeneralDecoder<char16be_t, wchar_t>;
|
|
extern template class UtfGeneralDecoder<char16be_t, char8_t>;
|
|
extern template class UtfGeneralDecoder<char16be_t, char16_t>;
|
|
extern template class UtfGeneralDecoder<char16be_t, char16be_t>;
|
|
extern template class UtfGeneralDecoder<char16be_t, char32_t>;
|
|
|
|
extern template class UtfGeneralDecoder<char32_t, wchar_t>;
|
|
extern template class UtfGeneralDecoder<char32_t, char8_t>;
|
|
extern template class UtfGeneralDecoder<char32_t, char16_t>;
|
|
extern template class UtfGeneralDecoder<char32_t, char16be_t>;
|
|
extern template class UtfGeneralDecoder<char32_t, char32_t>;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/***********************************************************************
|
|
.\ENCODING\CHARFORMAT\CHARFORMAT.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_STREAM_ENCODING_CHARFORMAT
|
|
#define VCZH_STREAM_ENCODING_CHARFORMAT
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace stream
|
|
{
|
|
/***********************************************************************
|
|
Utf-8
|
|
***********************************************************************/
|
|
|
|
/// <summary>Encoder to write UTF-8 text.</summary>
|
|
class Utf8Encoder : public UtfGeneralEncoder<char8_t, wchar_t> {};
|
|
/// <summary>Decoder to read UTF-8 text.</summary>
|
|
class Utf8Decoder : public UtfGeneralDecoder<char8_t, wchar_t> {};
|
|
|
|
/***********************************************************************
|
|
Utf-16
|
|
***********************************************************************/
|
|
|
|
/// <summary>Encoder to write UTF-16 text.</summary>
|
|
class Utf16Encoder : public UtfGeneralEncoder<char16_t, wchar_t> {};
|
|
/// <summary>Decoder to read UTF-16 text.</summary>
|
|
class Utf16Decoder : public UtfGeneralDecoder<char16_t, wchar_t> {};
|
|
|
|
/***********************************************************************
|
|
Utf-16BE
|
|
***********************************************************************/
|
|
|
|
/// <summary>Encoder to write big endian UTF-16 to.</summary>
|
|
class Utf16BEEncoder : public UtfGeneralEncoder<char16be_t, wchar_t> {};
|
|
/// <summary>Decoder to read big endian UTF-16 text.</summary>
|
|
class Utf16BEDecoder : public UtfGeneralDecoder<char16be_t, wchar_t> {};
|
|
|
|
/***********************************************************************
|
|
Utf-32
|
|
***********************************************************************/
|
|
|
|
/// <summary>Encoder to write UTF-8 text.</summary>
|
|
class Utf32Encoder : public UtfGeneralEncoder<char32_t, wchar_t> {};
|
|
/// <summary>Decoder to read UTF-8 text.</summary>
|
|
class Utf32Decoder : public UtfGeneralDecoder<char32_t, wchar_t> {};
|
|
|
|
/***********************************************************************
|
|
Encoding Test
|
|
***********************************************************************/
|
|
|
|
/// <summary>Guess the text encoding in a buffer.</summary>
|
|
/// <param name="buffer">The buffer to guess.</param>
|
|
/// <param name="size">Size of the buffer in bytes.</param>
|
|
/// <param name="encoding">Returns the most possible encoding.</param>
|
|
/// <param name="containsBom">Returns true if the BOM information is at the beginning of the buffer.</param>
|
|
extern void TestEncoding(unsigned char* buffer, vint size, BomEncoder::Encoding& encoding, bool& containsBom);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/***********************************************************************
|
|
.\ENCODING\LZWENCODING.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_STREAM_ENCODING_LZWENCODING
|
|
#define VCZH_STREAM_ENCODING_LZWENCODING
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace stream
|
|
{
|
|
|
|
/***********************************************************************
|
|
Compression
|
|
***********************************************************************/
|
|
|
|
namespace lzw
|
|
{
|
|
static const vint BufferSize = 1024;
|
|
static const vint MaxDictionarySize = 1 << 24;
|
|
|
|
struct Code
|
|
{
|
|
typedef collections::PushOnlyAllocator<Code> CodeAllocator;
|
|
typedef collections::ByteObjectMap<Code>::Allocator MapAllocator;
|
|
|
|
vuint8_t byte = 0;
|
|
vint code = -1;
|
|
Code* parent = 0;
|
|
vint size = 0;
|
|
collections::ByteObjectMap<Code> children;
|
|
};
|
|
}
|
|
|
|
class LzwBase : public Object
|
|
{
|
|
protected:
|
|
lzw::Code::CodeAllocator codeAllocator;
|
|
lzw::Code::MapAllocator mapAllocator;
|
|
lzw::Code* root;
|
|
vint eofIndex = -1;
|
|
vint nextIndex = 0;
|
|
vint indexBits = 1;
|
|
|
|
void UpdateIndexBits();
|
|
lzw::Code* CreateCode(lzw::Code* parent, vuint8_t byte);
|
|
|
|
LzwBase();
|
|
LzwBase(bool (&existingBytes)[256]);
|
|
~LzwBase();
|
|
};
|
|
|
|
/// <summary>An encoder to compress data using the Lzw algorithm.</summary>
|
|
/// <remarks>
|
|
/// You are not recommended to compress data more than 1 mega bytes at once using the encoder directly.
|
|
/// <see cref="CompressStream"/> and <see cref="DecompressStream"/> is recommended.
|
|
/// </remarks>
|
|
class LzwEncoder : public LzwBase, public EncoderBase
|
|
{
|
|
protected:
|
|
vuint8_t buffer[lzw::BufferSize];
|
|
vint bufferUsedBits = 0;
|
|
lzw::Code* prefix;
|
|
|
|
void Flush();
|
|
void WriteNumber(vint number, vint bitSize);
|
|
public:
|
|
/// <summary>Create an encoder.</summary>
|
|
LzwEncoder();
|
|
/// <summary>Create an encoder, specifying what bytes will never appear in the data to compress.</summary>
|
|
/// <param name="existingBytes">
|
|
/// A filter array
|
|
/// If existingBytes[x] == true, it means x will possibly appear.
|
|
/// If existingBytes[x] == false, it means x will never appear.
|
|
/// </param>
|
|
/// <remarks>
|
|
/// The behavior is undefined, if existingBytes[x] == false, but byte x is actually in the data to compress.
|
|
/// </remarks>
|
|
LzwEncoder(bool (&existingBytes)[256]);
|
|
~LzwEncoder();
|
|
|
|
void Close()override;
|
|
vint Write(void* _buffer, vint _size)override;
|
|
};
|
|
|
|
/// <summary>An decoder to decompress data using the Lzw algorithm.</summary>
|
|
/// <remarks>
|
|
/// You are not recommended to compress data more than 1 mega bytes at once using the encoder directly.
|
|
/// <see cref="CompressStream"/> and <see cref="DecompressStream"/> is recommended.
|
|
/// </remarks>
|
|
class LzwDecoder :public LzwBase, public DecoderBase
|
|
{
|
|
protected:
|
|
collections::List<lzw::Code*> dictionary;
|
|
lzw::Code* lastCode = 0;
|
|
|
|
vuint8_t inputBuffer[lzw::BufferSize];
|
|
vint inputBufferSize = 0;
|
|
vint inputBufferUsedBits = 0;
|
|
|
|
collections::Array<vuint8_t> outputBuffer;
|
|
vint outputBufferSize = 0;
|
|
vint outputBufferUsedBytes = 0;
|
|
|
|
bool ReadNumber(vint& number, vint bitSize);
|
|
void PrepareOutputBuffer(vint size);
|
|
void ExpandCodeToOutputBuffer(lzw::Code* code);
|
|
public:
|
|
/// <summary>Create a decoder.</summary>
|
|
LzwDecoder();
|
|
/// <summary>Create an encoder, specifying what bytes will never appear in the decompressed data.</summary>
|
|
/// <param name="existingBytes">
|
|
/// A filter array
|
|
/// If existingBytes[x] == true, it means x will possibly appear.
|
|
/// If existingBytes[x] == false, it means x will never appear.
|
|
/// </param>
|
|
/// <remarks>
|
|
/// The array "existingBytes" should exactly match the one given to <see cref="LzwEncoder"/>.
|
|
/// </remarks>
|
|
LzwDecoder(bool (&existingBytes)[256]);
|
|
~LzwDecoder();
|
|
|
|
vint Read(void* _buffer, vint _size)override;
|
|
};
|
|
|
|
/***********************************************************************
|
|
Helper Functions
|
|
***********************************************************************/
|
|
|
|
/// <summary>Copy data from a <b>readable</b> input stream to a <b>writable</b> output stream.</summary>
|
|
/// <returns>Data copied in bytes.</returns>
|
|
/// <param name="inputStream">The <b>readable</b> input stream.</param>
|
|
/// <param name="outputStream">The <b>writable</b> output stream.</param>
|
|
extern vint CopyStream(stream::IStream& inputStream, stream::IStream& outputStream);
|
|
|
|
/// <summary>Compress data from a <b>readable</b> input stream to a <b>writable</b> output stream.</summary>
|
|
/// <returns>Data copied in bytes.</returns>
|
|
/// <param name="inputStream">The <b>readable</b> input stream.</param>
|
|
/// <param name="outputStream">The <b>writable</b> output stream.</param>
|
|
/// <remarks>
|
|
/// 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.
|
|
/// </remarks>
|
|
/// <example><![CDATA[
|
|
/// int main()
|
|
/// {
|
|
/// MemoryStream textStream, compressedStream, decompressedStream;
|
|
/// {
|
|
/// Utf8Encoder encoder;
|
|
/// EncoderStream encoderStream(textStream, encoder);
|
|
/// StreamWriter writer(encoderStream);
|
|
/// writer.WriteString(L"Some text to compress.");
|
|
/// }
|
|
/// textStream.SeekFromBegin(0);
|
|
///
|
|
/// CompressStream(textStream, compressedStream);
|
|
/// compressedStream.SeekFromBegin(0);
|
|
/// DecompressStream(compressedStream, decompressedStream);
|
|
/// decompressedStream.SeekFromBegin(0);
|
|
///
|
|
/// Utf8Decoder decoder;
|
|
/// DecoderStream decoderStream(decompressedStream, decoder);
|
|
/// StreamReader reader(decoderStream);
|
|
/// Console::WriteLine(reader.ReadToEnd());
|
|
/// }
|
|
/// ]]></example>
|
|
extern void CompressStream(stream::IStream& inputStream, stream::IStream& outputStream);
|
|
|
|
/// <summary>Decompress data from a <b>readable</b> input stream (with compressed data) to a <b>writable</b> output stream (with uncompressed data).</summary>
|
|
/// <returns>Data copied in bytes.</returns>
|
|
/// <param name="inputStream">The <b>readable</b> input stream.</param>
|
|
/// <param name="outputStream">The <b>writable</b> output stream.</param>
|
|
/// <remarks>
|
|
/// 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.
|
|
/// </remarks>
|
|
/// <example><![CDATA[
|
|
/// int main()
|
|
/// {
|
|
/// MemoryStream textStream, compressedStream, decompressedStream;
|
|
/// {
|
|
/// Utf8Encoder encoder;
|
|
/// EncoderStream encoderStream(textStream, encoder);
|
|
/// StreamWriter writer(encoderStream);
|
|
/// writer.WriteString(L"Some text to compress.");
|
|
/// }
|
|
/// textStream.SeekFromBegin(0);
|
|
///
|
|
/// CompressStream(textStream, compressedStream);
|
|
/// compressedStream.SeekFromBegin(0);
|
|
/// DecompressStream(compressedStream, decompressedStream);
|
|
/// decompressedStream.SeekFromBegin(0);
|
|
///
|
|
/// Utf8Decoder decoder;
|
|
/// DecoderStream decoderStream(decompressedStream, decoder);
|
|
/// StreamReader reader(decoderStream);
|
|
/// Console::WriteLine(reader.ReadToEnd());
|
|
/// }
|
|
/// ]]></example>
|
|
extern void DecompressStream(stream::IStream& inputStream, stream::IStream& outputStream);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\STREAM\BROADCASTSTREAM.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_STREAM_BROADCASTSTREAM
|
|
#define VCZH_STREAM_BROADCASTSTREAM
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace stream
|
|
{
|
|
/// <summary>A <b>writable</b> stream that copy the written content to multiple output streams.</summary>
|
|
/// <remarks>
|
|
/// When writing happens, the boreadcast stream will only performance one write attempt to each output stream.
|
|
/// </remarks>
|
|
class BroadcastStream : public Object, public virtual IStream
|
|
{
|
|
typedef collections::List<IStream*> StreamList;
|
|
protected:
|
|
bool closed;
|
|
pos_t position;
|
|
StreamList streams;
|
|
public:
|
|
/// <summary>Create a boradcast stream.</summary>
|
|
BroadcastStream();
|
|
~BroadcastStream();
|
|
|
|
/// <summary>
|
|
/// Get the list of output streams.
|
|
/// You can change this list to subscribe or unsubscribe.
|
|
/// </summary>
|
|
/// <returns>The list of output streams.</returns>
|
|
StreamList& Targets();
|
|
bool CanRead()const;
|
|
bool CanWrite()const;
|
|
bool CanSeek()const;
|
|
bool CanPeek()const;
|
|
bool IsLimited()const;
|
|
bool IsAvailable()const;
|
|
void Close();
|
|
pos_t Position()const;
|
|
pos_t Size()const;
|
|
void Seek(pos_t _size);
|
|
void SeekFromBegin(pos_t _size);
|
|
void SeekFromEnd(pos_t _size);
|
|
vint Read(void* _buffer, vint _size);
|
|
vint Write(void* _buffer, vint _size);
|
|
vint Peek(void* _buffer, vint _size);
|
|
};
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\STREAM\CACHESTREAM.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_STREAM_CACHESTREAM
|
|
#define VCZH_STREAM_CACHESTREAM
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace stream
|
|
{
|
|
/// <summary>
|
|
/// <p>
|
|
/// A potentially <b>readable</b>, <b>peekable</b>, <b>writable</b>, <b>seekable</b> and <b>finite</b> stream that creates on another stream.
|
|
/// Each feature is available if the target stream has the same feature.
|
|
/// </p>
|
|
/// <p>
|
|
/// 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.
|
|
/// </p>
|
|
/// <p>
|
|
/// 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.
|
|
/// </p>
|
|
/// </summary>
|
|
class CacheStream : public Object, public virtual IStream
|
|
{
|
|
protected:
|
|
IStream* target;
|
|
vint block;
|
|
pos_t start;
|
|
pos_t position;
|
|
|
|
char* buffer;
|
|
vint dirtyStart;
|
|
vint dirtyLength;
|
|
vint availableLength;
|
|
pos_t operatedSize;
|
|
|
|
void Flush();
|
|
void Load(pos_t _position);
|
|
vint InternalRead(void* _buffer, vint _size);
|
|
vint InternalWrite(void* _buffer, vint _size);
|
|
public:
|
|
/// <summary>Create a cache stream from a target stream.</summary>
|
|
/// <param name="_target">The target stream.</param>
|
|
/// <param name="_block">Size of the cache.</param>
|
|
CacheStream(IStream& _target, vint _block=65536);
|
|
~CacheStream();
|
|
|
|
bool CanRead()const;
|
|
bool CanWrite()const;
|
|
bool CanSeek()const;
|
|
bool CanPeek()const;
|
|
bool IsLimited()const;
|
|
bool IsAvailable()const;
|
|
void Close();
|
|
pos_t Position()const;
|
|
pos_t Size()const;
|
|
void Seek(pos_t _size);
|
|
void SeekFromBegin(pos_t _size);
|
|
void SeekFromEnd(pos_t _size);
|
|
vint Read(void* _buffer, vint _size);
|
|
vint Write(void* _buffer, vint _size);
|
|
vint Peek(void* _buffer, vint _size);
|
|
};
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\STREAM\ENCODINGSTREAM.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_STREAM_ENCODINGSTREAM
|
|
#define VCZH_STREAM_ENCODINGSTREAM
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace stream
|
|
{
|
|
/***********************************************************************
|
|
Encoding Related
|
|
***********************************************************************/
|
|
|
|
/// <summary>Encoder stream, a <b>writable</b> and potentially <b>finite</b> stream using [T:vl.stream.IEncoder] to transform content.</summary>
|
|
class EncoderStream : public virtual IStream
|
|
{
|
|
protected:
|
|
IStream* stream;
|
|
IEncoder* encoder;
|
|
pos_t position;
|
|
|
|
public:
|
|
/// <summary>Create en encoder stream.</summary>
|
|
/// <param name="_stream">The output stream to write.</param>
|
|
/// <param name="_encoder">The encoder to transform content.</param>
|
|
EncoderStream(IStream& _stream, IEncoder& _encoder);
|
|
~EncoderStream();
|
|
|
|
bool CanRead()const;
|
|
bool CanWrite()const;
|
|
bool CanSeek()const;
|
|
bool CanPeek()const;
|
|
bool IsLimited()const;
|
|
bool IsAvailable()const;
|
|
void Close();
|
|
pos_t Position()const;
|
|
pos_t Size()const;
|
|
void Seek(pos_t _size);
|
|
void SeekFromBegin(pos_t _size);
|
|
void SeekFromEnd(pos_t _size);
|
|
vint Read(void* _buffer, vint _size);
|
|
vint Write(void* _buffer, vint _size);
|
|
vint Peek(void* _buffer, vint _size);
|
|
};
|
|
|
|
/// <summary>Decoder stream, a <b>readable</b> and potentially <b>finite</b> stream using [T:vl.stream.IDecoder] to transform content.</summary>
|
|
class DecoderStream : public virtual IStream
|
|
{
|
|
protected:
|
|
IStream* stream;
|
|
IDecoder* decoder;
|
|
pos_t position;
|
|
|
|
public:
|
|
/// <summary>Create a decoder stream.</summary>
|
|
/// <param name="_stream">The input stream to read.</param>
|
|
/// <param name="_decoder">The decoder to transform content.</param>
|
|
DecoderStream(IStream& _stream, IDecoder& _decoder);
|
|
~DecoderStream();
|
|
|
|
bool CanRead()const;
|
|
bool CanWrite()const;
|
|
bool CanSeek()const;
|
|
bool CanPeek()const;
|
|
bool IsLimited()const;
|
|
bool IsAvailable()const;
|
|
void Close();
|
|
pos_t Position()const;
|
|
pos_t Size()const;
|
|
void Seek(pos_t _size);
|
|
void SeekFromBegin(pos_t _size);
|
|
void SeekFromEnd(pos_t _size);
|
|
vint Read(void* _buffer, vint _size);
|
|
vint Write(void* _buffer, vint _size);
|
|
vint Peek(void* _buffer, vint _size);
|
|
};
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\STREAM\FILESTREAM.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_STREAM_FILESTREAM
|
|
#define VCZH_STREAM_FILESTREAM
|
|
|
|
#include <stdio.h>
|
|
|
|
namespace vl
|
|
{
|
|
namespace stream
|
|
{
|
|
/// <summary>Platform-specific file stream implementation interface.</summary>
|
|
class IFileStreamImpl : public virtual Interface
|
|
{
|
|
public:
|
|
virtual bool Open() = 0;
|
|
virtual void Close() = 0;
|
|
virtual pos_t Position() const = 0;
|
|
virtual pos_t Size() const = 0;
|
|
virtual void Seek(pos_t _size) = 0;
|
|
virtual void SeekFromBegin(pos_t _size) = 0;
|
|
virtual void SeekFromEnd(pos_t _size) = 0;
|
|
virtual vint Read(void* _buffer, vint _size) = 0;
|
|
virtual vint Write(void* _buffer, vint _size) = 0;
|
|
virtual vint Peek(void* _buffer, vint _size) = 0;
|
|
};
|
|
|
|
/// <summary>A file stream. If the given file name is not working, the stream could be <b>unavailable</b>.</summary>
|
|
class FileStream : public Object, public virtual IStream
|
|
{
|
|
public:
|
|
/// <summary>Access to the file.</summary>
|
|
enum AccessRight
|
|
{
|
|
/// <summary>The file is opened to read, making this stream <b>readable</b>, <b>seekable</b> and <b>finite</b>.</summary>
|
|
ReadOnly,
|
|
/// <summary>The file is opened to write, making this stream <b>writable</b>.</summary>
|
|
WriteOnly,
|
|
/// <summary>The file is opened to both read and write, making this stream <b>readable</b>, <b>seekable</b> and <b>writable</b>.</summary>
|
|
ReadWrite
|
|
};
|
|
protected:
|
|
AccessRight accessRight;
|
|
Ptr<IFileStreamImpl> impl;
|
|
public:
|
|
/// <summary>Create a file stream from a given file name.</summary>
|
|
/// <param name="fileName">The file to operate.</param>
|
|
/// <param name="_accessRight">Expected operations on the file.</param>
|
|
FileStream(const WString& fileName, AccessRight _accessRight);
|
|
~FileStream();
|
|
|
|
bool CanRead()const;
|
|
bool CanWrite()const;
|
|
bool CanSeek()const;
|
|
bool CanPeek()const;
|
|
bool IsLimited()const;
|
|
bool IsAvailable()const;
|
|
void Close();
|
|
pos_t Position()const;
|
|
pos_t Size()const;
|
|
void Seek(pos_t _size);
|
|
void SeekFromBegin(pos_t _size);
|
|
void SeekFromEnd(pos_t _size);
|
|
vint Read(void* _buffer, vint _size);
|
|
vint Write(void* _buffer, vint _size);
|
|
vint Peek(void* _buffer, vint _size);
|
|
};
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\FILESYSTEM.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_FILESYSTEM
|
|
#define VCZH_FILESYSTEM
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace filesystem
|
|
{
|
|
/// <summary>Absolute file path.</summary>
|
|
class FilePath : public Object
|
|
{
|
|
friend class LinuxFileSystemImpl;
|
|
friend class WindowsFileSystemImpl;
|
|
protected:
|
|
WString fullPath;
|
|
|
|
static void NormalizeDelimiters(collections::Array<wchar_t>& buffer);
|
|
static void TrimLastDelimiter(WString& fullPath);
|
|
void Initialize();
|
|
|
|
static void GetPathComponents(WString path, collections::List<WString>& components);
|
|
static WString ComponentsToPath(const collections::List<WString>& components);
|
|
public:
|
|
#if defined VCZH_MSVC
|
|
/// <summary>The delimiter character used in a file path</summary>
|
|
/// <remarks>
|
|
/// In Windows, it is "\".
|
|
/// In Linux and macOS, it is "/".
|
|
/// But you can always use "/", it is also supported in Windows.
|
|
/// </remarks>
|
|
static constexpr wchar_t Delimiter = L'\\';
|
|
#elif defined VCZH_GCC
|
|
static constexpr wchar_t Delimiter = L'/';
|
|
#endif
|
|
|
|
/// <summary>Create a root path.</summary>
|
|
/// <remarks><see cref="GetFullPath"/> returns different values for root path on different platforms. Do not rely on the value.</remarks>
|
|
FilePath();
|
|
/// <summary>Create a file path.</summary>
|
|
/// <param name="_filePath">Content of the file path. If it is a relative path, it will be converted to an absolute path.</param>
|
|
FilePath(const WString& _filePath);
|
|
/// <summary>Create a file path.</summary>
|
|
/// <param name="_filePath">Content of the file path. If it is a relative path, it will be converted to an absolute path.</param>
|
|
FilePath(const wchar_t* _filePath);
|
|
/// <summary>Copy a file path.</summary>
|
|
/// <param name="_filePath">The file path to copy.</param>
|
|
FilePath(const FilePath& _filePath);
|
|
~FilePath() = default;
|
|
|
|
std::strong_ordering operator<=>(const FilePath& path)const { return fullPath <=> path.fullPath; }
|
|
bool operator==(const FilePath& path)const { return fullPath == path.fullPath; }
|
|
|
|
/// <summary>Concat an absolute path and a relative path.</summary>
|
|
/// <returns>The result absolute path.</returns>
|
|
/// <param name="relativePath">The relative path to concat.</param>
|
|
FilePath operator/(const WString& relativePath)const;
|
|
|
|
/// <summary>Test if the file path is a file.</summary>
|
|
/// <returns>Returns true if the file path is a file.</returns>
|
|
bool IsFile()const;
|
|
/// <summary>Test if the file path is a folder.</summary>
|
|
/// <returns>Returns true if the file path is a folder.</returns>
|
|
/// <remarks>In Windows, a drive is also considered a folder.</remarks>
|
|
bool IsFolder()const;
|
|
/// <summary>Test if the file path is a the root of all file system objects.</summary>
|
|
/// <returns>Returns true if the file path is the root of all file system objects.</returns>
|
|
bool IsRoot()const;
|
|
|
|
/// <summary>Get the last piece of names in the file path.</summary>
|
|
/// <returns>The last piece of names in the file path.</returns>
|
|
WString GetName()const;
|
|
/// <summary>Get the containing folder of this file path.</summary>
|
|
/// <returns>The containing folder.</returns>
|
|
FilePath GetFolder()const;
|
|
/// <summary>Get the content of the file path.</summary>
|
|
/// <returns>The content of the file path.</returns>
|
|
WString GetFullPath()const;
|
|
/// <summary>Calculate the relative path based on a specified referencing folder.</summary>
|
|
/// <returns>The relative path.</returns>
|
|
/// <param name="_filePath">The referencing folder.</param>
|
|
WString GetRelativePathFor(const FilePath& _filePath)const;
|
|
|
|
};
|
|
|
|
/// <summary>A file.</summary>
|
|
class File : public Object
|
|
{
|
|
private:
|
|
FilePath filePath;
|
|
|
|
public:
|
|
/// <summary>Create an empty reference. An empty reference does not refer to any file.</summary>
|
|
File() = default;
|
|
/// <summary>Create a reference to a specified file. The file is not required to exist.</summary>
|
|
/// <param name="_filePath">The specified file.</param>
|
|
File(const FilePath& _filePath);
|
|
~File() = default;
|
|
|
|
/// <summary>Get the file path of the file.</summary>
|
|
/// <returns>The file path.</returns>
|
|
const FilePath& GetFilePath()const;
|
|
|
|
/// <summary>Get the content of a text file with encoding testing.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="text">Returns the content of the file.</param>
|
|
/// <param name="encoding">Returns the encoding of the file.</param>
|
|
/// <param name="containsBom">Returns true if there is a BOM in the file.</param>
|
|
bool ReadAllTextWithEncodingTesting(WString& text, stream::BomEncoder::Encoding& encoding, bool& containsBom);
|
|
/// <summary>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.</summary>
|
|
/// <returns>The content of the file.</returns>
|
|
WString ReadAllTextByBom()const;
|
|
/// <summary>Get the content of a text file.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="text">The content of the file.</param>
|
|
bool ReadAllTextByBom(WString& text)const;
|
|
/// <summary>Get the content of a text file by lines.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="lines">The content of the file by lines.</param>
|
|
/// <remarks>
|
|
/// 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.
|
|
/// </remarks>
|
|
bool ReadAllLinesByBom(collections::List<WString>& lines)const;
|
|
|
|
/// <summary>Write text to the file.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="text">The text to write.</param>
|
|
/// <param name="bom">Set to true to add a corresponding BOM at the beginning of the file according to the encoding, the default value is true.</param>
|
|
/// <param name="encoding">The text encoding, the default encoding is UTF-16.</param>
|
|
bool WriteAllText(const WString& text, bool bom = true, stream::BomEncoder::Encoding encoding = stream::BomEncoder::Utf16);
|
|
/// <summary>Write text to the file.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="lines">The text to write, with CRLF appended after all lines.</param>
|
|
/// <param name="bom">Set to true to add a corresponding BOM at the beginning of the file according to the encoding, the default value is true.</param>
|
|
/// <param name="encoding">The text encoding, the default encoding is UTF-16.</param>
|
|
bool WriteAllLines(collections::List<WString>& lines, bool bom = true, stream::BomEncoder::Encoding encoding = stream::BomEncoder::Utf16);
|
|
|
|
/// <summary>Test does the file exist or not.</summary>
|
|
/// <returns>Returns true if the file exists.</returns>
|
|
bool Exists()const;
|
|
/// <summary>Delete the file.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <remarks>This function could return before the file is actually deleted.</remarks>
|
|
bool Delete()const;
|
|
/// <summary>Rename the file.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="newName">The new file name.</param>
|
|
bool Rename(const WString& newName)const;
|
|
};
|
|
|
|
/// <summary>A folder.</summary>
|
|
/// <remarks>In Windows, a drive is also considered a folder.</remarks>
|
|
class Folder : public Object
|
|
{
|
|
private:
|
|
FilePath filePath;
|
|
|
|
bool CreateNonRecursively()const;
|
|
bool DeleteNonRecursively()const;
|
|
public:
|
|
/// <summary>Create a reference to the root folder.</summary>
|
|
Folder() = default;
|
|
/// <summary>Create a reference to a specified folder. The folder is not required to exist.</summary>
|
|
/// <param name="_filePath">The specified folder.</param>
|
|
Folder(const FilePath& _filePath);
|
|
~Folder() = default;
|
|
|
|
/// <summary>Get the file path of the folder.</summary>
|
|
/// <returns>The file path.</returns>
|
|
const FilePath& GetFilePath()const;
|
|
/// <summary>Get all folders in this folder.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="folders">All folders.</param>
|
|
/// <remarks>In Windows, drives are considered sub folders in the root folder.</remarks>
|
|
bool GetFolders(collections::List<Folder>& folders)const;
|
|
/// <summary>Get all files in this folder.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="files">All files.</param>
|
|
bool GetFiles(collections::List<File>& files)const;
|
|
|
|
/// <summary>Test does the folder exist or not.</summary>
|
|
/// <returns>Returns true if the folder exists.</returns>
|
|
bool Exists()const;
|
|
/// <summary>Create the folder.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="recursively">Set to true to create all levels of containing folders if they do not exist.</param>
|
|
/// <remarks>
|
|
/// 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.
|
|
/// </remarks>
|
|
bool Create(bool recursively)const;
|
|
/// <summary>Delete the folder.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="recursively">Set to true to delete everything in the folder.</param>
|
|
/// <remarks>This function could return before the folder is actually deleted.</remarks>
|
|
bool Delete(bool recursively)const;
|
|
/// <summary>Rename the folder.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
/// <param name="newName">The new folder name.</param>
|
|
bool Rename(const WString& newName)const;
|
|
};
|
|
|
|
/// <summary>Platform-specific file system implementation interface.</summary>
|
|
class IFileSystemImpl : public virtual feature_injection::IFeatureImpl
|
|
{
|
|
public:
|
|
// FilePath operations
|
|
virtual void Initialize(WString& fullPath) const = 0;
|
|
virtual bool IsFile(const WString& fullPath) const = 0;
|
|
virtual bool IsFolder(const WString& fullPath) const = 0;
|
|
virtual bool IsRoot(const WString& fullPath) const = 0;
|
|
virtual WString GetRelativePathFor(const WString& fromPath, const WString& toPath) const = 0;
|
|
|
|
// File operations
|
|
virtual bool FileDelete(const FilePath& filePath) const = 0;
|
|
virtual bool FileRename(const FilePath& filePath, const WString& newName) const = 0;
|
|
|
|
// Folder operations
|
|
virtual bool GetFolders(const FilePath& folderPath, collections::List<Folder>& folders) const = 0;
|
|
virtual bool GetFiles(const FilePath& folderPath, collections::List<File>& files) const = 0;
|
|
virtual bool CreateFolder(const FilePath& folderPath) const = 0;
|
|
virtual bool DeleteFolder(const FilePath& folderPath) const = 0;
|
|
virtual bool FolderRename(const FilePath& folderPath, const WString& newName) const = 0;
|
|
|
|
// Stream operations
|
|
virtual Ptr<stream::IFileStreamImpl> GetFileStreamImpl(const WString& fileName, stream::FileStream::AccessRight accessRight) const = 0;
|
|
};
|
|
|
|
extern void InjectFileSystemImpl(IFileSystemImpl* impl);
|
|
extern void EjectFileSystemImpl(IFileSystemImpl* impl);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/***********************************************************************
|
|
.\STREAM\MEMORYSTREAM.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_STREAM_MEMORYSTREAM
|
|
#define VCZH_STREAM_MEMORYSTREAM
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace stream
|
|
{
|
|
/// <summary>A <b>readable</b>, <b>peekable</b>, <b>writable</b> and <b>seekable</b> stream that creates on a buffer.</summary>
|
|
class MemoryStream : public Object, public virtual IStream
|
|
{
|
|
protected:
|
|
vint block;
|
|
char* buffer;
|
|
vint size;
|
|
vint position;
|
|
vint capacity;
|
|
|
|
void PrepareSpace(vint totalSpace);
|
|
public:
|
|
/// <summary>Create a memory stream.</summary>
|
|
/// <param name="_block">
|
|
/// 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.
|
|
/// </param>
|
|
MemoryStream(vint _block=65536);
|
|
~MemoryStream();
|
|
|
|
bool CanRead()const;
|
|
bool CanWrite()const;
|
|
bool CanSeek()const;
|
|
bool CanPeek()const;
|
|
bool IsLimited()const;
|
|
bool IsAvailable()const;
|
|
void Close();
|
|
pos_t Position()const;
|
|
pos_t Size()const;
|
|
void Seek(pos_t _size);
|
|
void SeekFromBegin(pos_t _size);
|
|
void SeekFromEnd(pos_t _size);
|
|
vint Read(void* _buffer, vint _size);
|
|
vint Write(void* _buffer, vint _size);
|
|
vint Peek(void* _buffer, vint _size);
|
|
void* GetInternalBuffer();
|
|
};
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\STREAM\ACCESSOR.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_STREAM_ACCESSOR
|
|
#define VCZH_STREAM_ACCESSOR
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace stream
|
|
{
|
|
|
|
/***********************************************************************
|
|
Text Related
|
|
***********************************************************************/
|
|
|
|
/// <summary>Text reader. All line breaks are normalized to CRLF regardless whatever in the input stream.</summary>
|
|
/// <typeparam name="T">The character type.</typeparam>
|
|
template<typename T>
|
|
class TextReader_ : public Object
|
|
{
|
|
public:
|
|
NOT_COPYABLE(TextReader_);
|
|
TextReader_() = default;
|
|
|
|
/// <summary>Test does the reader reach the end or not.</summary>
|
|
/// <returns>Returns true if the reader reaches the end.</returns>
|
|
virtual bool IsEnd()=0;
|
|
/// <summary>Read a single character.</summary>
|
|
/// <returns>The character.</returns>
|
|
virtual T ReadChar()=0;
|
|
/// <summary>Read a string of a specified size in characters.</summary>
|
|
/// <returns>The read string. It could be shorter than the expected length if the reader reaches the end.</returns>
|
|
/// <param name="length">Expected length of the string to read.</param>
|
|
virtual ObjectString<T> ReadString(vint length);
|
|
/// <summary>Read a string until a line breaks is reached.</summary>
|
|
/// <returns>The string without the line break. If the reader reaches the end, it returns an empty string.</returns>
|
|
virtual ObjectString<T> ReadLine();
|
|
/// <summary>Read everying remain.</summary>
|
|
/// <returns>The read string.</returns>
|
|
virtual ObjectString<T> ReadToEnd();
|
|
};
|
|
|
|
/// <summary>Text writer.</summary>
|
|
/// <typeparam name="T">The character type.</typeparam>
|
|
template<typename T>
|
|
class TextWriter_ : public Object
|
|
{
|
|
public:
|
|
NOT_COPYABLE(TextWriter_);
|
|
TextWriter_() = default;
|
|
|
|
/// <summary>Write a single character.</summary>
|
|
/// <param name="c">The character to write.</param>
|
|
virtual void WriteChar(T c)=0;
|
|
/// <summary>Write a string.</summary>
|
|
/// <param name="string">Buffer of the string to write.</param>
|
|
/// <param name="charCount">Size of the string in characters, not including the zero terminator.</param>
|
|
virtual void WriteString(const T* string, vint charCount);
|
|
/// <summary>Write a string.</summary>
|
|
/// <param name="string">Buffer of the zero terminated string to write.</param>
|
|
virtual void WriteString(const T* string);
|
|
/// <summary>Write a string.</summary>
|
|
/// <param name="string">The string to write.</param>
|
|
virtual void WriteString(const ObjectString<T>& string);
|
|
/// <summary>Write a string with a CRLF.</summary>
|
|
/// <param name="string">Buffer to the string to write.</param>
|
|
/// <param name="charCount">Size of the string in characters, not including the zero terminator.</param>
|
|
virtual void WriteLine(const T* string, vint charCount);
|
|
/// <summary>Write a string with a CRLF.</summary>
|
|
/// <param name="string">Buffer to the zero terminated string to write.</param>
|
|
virtual void WriteLine(const T* string);
|
|
/// <summary>Write a string with a CRLF.</summary>
|
|
/// <param name="string">The string to write.</param>
|
|
virtual void WriteLine(const ObjectString<T>& string);
|
|
};
|
|
|
|
/// <summary>Text reader from a string.</summary>
|
|
/// <typeparam name="T">The character type.</typeparam>
|
|
template<typename T>
|
|
class StringReader_ : public TextReader_<T>
|
|
{
|
|
protected:
|
|
ObjectString<T> string;
|
|
vint current;
|
|
bool lastCallIsReadLine;
|
|
|
|
void PrepareIfLastCallIsReadLine();
|
|
public:
|
|
/// <summary>Create a text reader.</summary>
|
|
/// <param name="_string">The string to read.</param>
|
|
StringReader_(const ObjectString<T>& _string);
|
|
|
|
bool IsEnd();
|
|
T ReadChar();
|
|
ObjectString<T> ReadString(vint length);
|
|
ObjectString<T> ReadLine();
|
|
ObjectString<T> ReadToEnd();
|
|
};
|
|
|
|
/// <summary>
|
|
/// Text reader from a stream storing characters in code point.
|
|
/// </summary>
|
|
/// <typeparam name="T">The character type.</typeparam>
|
|
/// <remarks>
|
|
/// To specify the encoding in the input stream,
|
|
/// you are recommended to create a <see cref="DecoderStream"/> with a <see cref="UtfGeneralDecoder"/> implementation,
|
|
/// like <see cref="BomDecoder"/>, <see cref="MbcsDecoder"/>, <see cref="Utf16Decoder"/>, <see cref="Utf16BEDecoder"/> or <see cref="Utf8Decoder"/>.
|
|
/// </remarks>
|
|
/// <example output="false"><![CDATA[
|
|
/// int main()
|
|
/// {
|
|
/// FileStream fileStream(L"C:/a.txt", FileStream::ReadOnly);
|
|
/// Utf8Decoder decoder;
|
|
/// DecoderStream decoderStream(fileStream, decoder);
|
|
/// StreamReader reader(decoderStream);
|
|
/// Console::WriteLine(reader.ReadToEnd());
|
|
/// }
|
|
/// ]]></example>
|
|
template<typename T>
|
|
class StreamReader_ : public TextReader_<T>
|
|
{
|
|
protected:
|
|
IStream* stream;
|
|
public:
|
|
/// <summary>Create a text reader.</summary>
|
|
/// <param name="_stream">The stream to read.</param>
|
|
StreamReader_(IStream& _stream);
|
|
|
|
bool IsEnd();
|
|
T ReadChar();
|
|
};
|
|
|
|
/// <summary>
|
|
/// Text reader from a stream storing characters in code point.
|
|
/// </summary>
|
|
/// <typeparam name="T">The character type.</typeparam>
|
|
/// <remarks>
|
|
/// To specify the encoding in the input stream,
|
|
/// you are recommended to create a <see cref="EncoderStream"/> with a <see cref="UtfGeneralEncoder"/> implementation,
|
|
/// like <see cref="BomEncoder"/>, <see cref="MbcsEncoder"/>, <see cref="Utf16Encoder"/>, <see cref="Utf16BEEncoder"/> or <see cref="Utf8Encoder"/>.
|
|
/// </remarks>
|
|
/// <example output="false"><![CDATA[
|
|
/// int main()
|
|
/// {
|
|
/// FileStream fileStream(L"C:/a.txt", FileStream::WriteOnly);
|
|
/// Utf8Encoder encoder;
|
|
/// EncoderStream encoderStream(fileStream, encoder);
|
|
/// StreamWriter writer(encoderStream);
|
|
/// writer.Write(L"Hello, world!");
|
|
/// }
|
|
/// ]]></example>
|
|
template<typename T>
|
|
class StreamWriter_ : public TextWriter_<T>
|
|
{
|
|
protected:
|
|
IStream* stream;
|
|
public:
|
|
/// <summary>Create a text writer.</summary>
|
|
/// <param name="_stream">The stream to write.</param>
|
|
StreamWriter_(IStream& _stream);
|
|
using TextWriter_<T>::WriteString;
|
|
|
|
void WriteChar(T c);
|
|
void WriteString(const T* string, vint charCount);
|
|
};
|
|
|
|
/***********************************************************************
|
|
Extern Templates
|
|
***********************************************************************/
|
|
|
|
extern template class TextReader_<wchar_t>;
|
|
extern template class TextReader_<char8_t>;
|
|
extern template class TextReader_<char16_t>;
|
|
extern template class TextReader_<char32_t>;
|
|
|
|
extern template class TextWriter_<wchar_t>;
|
|
extern template class TextWriter_<char8_t>;
|
|
extern template class TextWriter_<char16_t>;
|
|
extern template class TextWriter_<char32_t>;
|
|
|
|
extern template class StringReader_<wchar_t>;
|
|
extern template class StringReader_<char8_t>;
|
|
extern template class StringReader_<char16_t>;
|
|
extern template class StringReader_<char32_t>;
|
|
|
|
extern template class StreamReader_<wchar_t>;
|
|
extern template class StreamReader_<char8_t>;
|
|
extern template class StreamReader_<char16_t>;
|
|
extern template class StreamReader_<char32_t>;
|
|
|
|
extern template class StreamWriter_<wchar_t>;
|
|
extern template class StreamWriter_<char8_t>;
|
|
extern template class StreamWriter_<char16_t>;
|
|
extern template class StreamWriter_<char32_t>;
|
|
|
|
/***********************************************************************
|
|
Helper Functions
|
|
***********************************************************************/
|
|
|
|
using TextReader = TextReader_<wchar_t>;
|
|
using TextWriter = TextWriter_<wchar_t>;
|
|
using StringReader = StringReader_<wchar_t>;
|
|
using StreamReader = StreamReader_<wchar_t>;
|
|
using StreamWriter = StreamWriter_<wchar_t>;
|
|
|
|
void WriteMonospacedEnglishTable(TextWriter& writer, collections::Array<WString>& tableByRow, vint rows, vint columns);
|
|
|
|
/// <summary>
|
|
/// Build a big string using <see cref="StreamWriter"/>.
|
|
/// </summary>
|
|
/// <typeparam name="TCallback">The type of the callback.</typeparam>
|
|
/// <returns>The built big string.</returns>
|
|
/// <param name="callback">
|
|
/// The callback to receive a big string.
|
|
/// The argument is a reference to a <see cref="StreamWriter"/>.
|
|
/// After the callback is executed, everything written to the writer will be returned from "GenerateToStream".
|
|
/// </param>
|
|
/// <param name="block">Size of the cache in bytes.</param>
|
|
/// <example><
|
|
/// {
|
|
/// writer.WriteLine(L"Hello, world!");
|
|
/// writer.WriteLine(L"Welcome to Gaclib!");
|
|
/// }));
|
|
/// }
|
|
/// ]]></example>
|
|
template<typename TCallback>
|
|
WString GenerateToStream(const TCallback& callback, vint block = 65536)
|
|
{
|
|
MemoryStream stream(block);
|
|
{
|
|
StreamWriter writer(stream);
|
|
callback(writer);
|
|
}
|
|
stream.SeekFromBegin(0);
|
|
{
|
|
StreamReader reader(stream);
|
|
return reader.ReadToEnd();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\STREAM\MEMORYWRAPPERSTREAM.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_STREAM_MEMORYWRAPPERSTREAM
|
|
#define VCZH_STREAM_MEMORYWRAPPERSTREAM
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace stream
|
|
{
|
|
/// <summary>A <b>readable</b>, <b>peekable</b>, <b>writable</b>, <b>seekable</b> and <b>finite</b> stream that creates on a buffer.</summary>
|
|
class MemoryWrapperStream : public Object, public virtual IStream
|
|
{
|
|
protected:
|
|
char* buffer;
|
|
vint size;
|
|
vint position;
|
|
public:
|
|
/// <summary>Create a memory wrapper stream.</summary>
|
|
/// <param name="_buffer">The buffer to operate.</param>
|
|
/// <param name="_size">Size of the buffer in bytes.</param>
|
|
MemoryWrapperStream(void* _buffer, vint _size);
|
|
~MemoryWrapperStream();
|
|
|
|
bool CanRead()const;
|
|
bool CanWrite()const;
|
|
bool CanSeek()const;
|
|
bool CanPeek()const;
|
|
bool IsLimited()const;
|
|
bool IsAvailable()const;
|
|
void Close();
|
|
pos_t Position()const;
|
|
pos_t Size()const;
|
|
void Seek(pos_t _size);
|
|
void SeekFromBegin(pos_t _size);
|
|
void SeekFromEnd(pos_t _size);
|
|
vint Read(void* _buffer, vint _size);
|
|
vint Write(void* _buffer, vint _size);
|
|
vint Peek(void* _buffer, vint _size);
|
|
};
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\STREAM\RECORDERSTREAM.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_STREAM_RECORDERSTREAM
|
|
#define VCZH_STREAM_RECORDERSTREAM
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace stream
|
|
{
|
|
/// <summary>
|
|
/// A readable stream that, reads from one stream, and copy everything that is read to another stream.
|
|
/// The stream is <b>unavailable</b> if one of the input stream or the output stream is <b>unavailable</b>.
|
|
/// The stream is <b>readable</b>, and potentially <b>finite</b>.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// When reading happens, the recorder stream will only performance one write attempt to the output stream.
|
|
/// </remarks>
|
|
class RecorderStream : public Object, public virtual IStream
|
|
{
|
|
protected:
|
|
IStream* in;
|
|
IStream* out;
|
|
public:
|
|
/// <summary>Create a recorder stream.</summary>
|
|
/// <param name="_in">
|
|
/// The input stream.
|
|
/// This recorder stream is <b>readable</b> only when the input stream is <b>readable</b>
|
|
/// This recorder stream is <b>finite</b> only when the input stream is <b>finite</b>
|
|
/// </param>
|
|
/// <param name="_out">
|
|
/// The output stream.
|
|
/// </param>
|
|
RecorderStream(IStream& _in, IStream& _out);
|
|
~RecorderStream();
|
|
|
|
bool CanRead()const;
|
|
bool CanWrite()const;
|
|
bool CanSeek()const;
|
|
bool CanPeek()const;
|
|
bool IsLimited()const;
|
|
bool IsAvailable()const;
|
|
void Close();
|
|
pos_t Position()const;
|
|
pos_t Size()const;
|
|
void Seek(pos_t _size);
|
|
void SeekFromBegin(pos_t _size);
|
|
void SeekFromEnd(pos_t _size);
|
|
vint Read(void* _buffer, vint _size);
|
|
vint Write(void* _buffer, vint _size);
|
|
vint Peek(void* _buffer, vint _size);
|
|
};
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\STREAM\SERIALIZATION.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_STREAM_SERIALIZATION
|
|
#define VCZH_STREAM_SERIALIZATION
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace stream
|
|
{
|
|
/***********************************************************************
|
|
Serialization
|
|
***********************************************************************/
|
|
|
|
namespace internal
|
|
{
|
|
template<typename T>
|
|
struct Reader
|
|
{
|
|
stream::IStream& input;
|
|
T context;
|
|
|
|
Reader(stream::IStream& _input)
|
|
:input(_input)
|
|
, context(nullptr)
|
|
{
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
struct Writer
|
|
{
|
|
stream::IStream& output;
|
|
T context;
|
|
|
|
Writer(stream::IStream& _output)
|
|
:output(_output)
|
|
, context(nullptr)
|
|
{
|
|
}
|
|
};
|
|
|
|
using ContextFreeReader = Reader<void*>;
|
|
using ContextFreeWriter = Writer<void*>;
|
|
|
|
template<typename T>
|
|
struct Serialization
|
|
{
|
|
template<typename TIO>
|
|
static void IO(TIO& io, T& value);
|
|
};
|
|
|
|
template<typename TValue, typename TContext>
|
|
Reader<TContext>& operator<<(Reader<TContext>& reader, TValue& value)
|
|
{
|
|
Serialization<TValue>::IO(reader, value);
|
|
return reader;
|
|
}
|
|
|
|
template<typename TValue, typename TContext>
|
|
Writer<TContext>& operator<<(Writer<TContext>& writer, TValue& value)
|
|
{
|
|
Serialization<TValue>::IO(writer, value);
|
|
return writer;
|
|
}
|
|
|
|
/***********************************************************************
|
|
Serialization (integers)
|
|
***********************************************************************/
|
|
|
|
template<typename T>
|
|
struct Serialization_POD
|
|
{
|
|
template<typename TContext>
|
|
static void IO(Reader<TContext>& reader, T& value)
|
|
{
|
|
if (reader.input.Read(&value, sizeof(value)) != sizeof(value))
|
|
{
|
|
CHECK_FAIL(L"Deserialization failed.");
|
|
}
|
|
}
|
|
|
|
template<typename TContext>
|
|
static void IO(Writer<TContext>& writer, T& value)
|
|
{
|
|
if (writer.output.Write(&value, sizeof(value)) != sizeof(value))
|
|
{
|
|
CHECK_FAIL(L"Serialization failed.");
|
|
}
|
|
}
|
|
};
|
|
|
|
template<typename TValue, typename TData>
|
|
struct Serialization_DefaultConversion
|
|
{
|
|
static TValue ToValue(TData data)
|
|
{
|
|
return (TValue)data;
|
|
}
|
|
|
|
static TData FromValue(TValue value)
|
|
{
|
|
return (TData)value;
|
|
}
|
|
};
|
|
|
|
template<typename TValue, typename TData, typename TConversion = Serialization_DefaultConversion<TValue, TData>>
|
|
struct Serialization_Conversion
|
|
{
|
|
template<typename TContext>
|
|
static void IO(Reader<TContext>& reader, TValue& value)
|
|
{
|
|
TData data;
|
|
Serialization<TData>::IO(reader, data);
|
|
value = TConversion::ToValue(data);
|
|
}
|
|
|
|
template<typename TContext>
|
|
static void IO(Writer<TContext>& writer, TValue& value)
|
|
{
|
|
TData data = TConversion::FromValue(value);
|
|
Serialization<TData>::IO(writer, data);
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct Serialization<vint64_t> : Serialization_POD<vint64_t> {};
|
|
|
|
template<>
|
|
struct Serialization<vuint64_t> : Serialization_POD<vuint64_t> {};
|
|
|
|
template<>
|
|
struct Serialization<vint32_t> : Serialization_Conversion<vint32_t, vint64_t> {};
|
|
|
|
template<>
|
|
struct Serialization<vuint32_t> : Serialization_Conversion<vuint32_t, vuint64_t> {};
|
|
|
|
template<>
|
|
struct Serialization<vint16_t> : Serialization_POD<vint16_t> {};
|
|
|
|
template<>
|
|
struct Serialization<vuint16_t> : Serialization_POD<vuint16_t> {};
|
|
|
|
template<>
|
|
struct Serialization<vint8_t> : Serialization_POD<vint8_t> {};
|
|
|
|
template<>
|
|
struct Serialization<vuint8_t> : Serialization_POD<vuint8_t> {};
|
|
|
|
/***********************************************************************
|
|
Serialization (chars)
|
|
***********************************************************************/
|
|
|
|
template<>
|
|
struct Serialization<char> : Serialization_Conversion<char, vint64_t> {};
|
|
|
|
template<>
|
|
struct Serialization<wchar_t> : Serialization_Conversion<wchar_t, vint64_t> {};
|
|
|
|
template<>
|
|
struct Serialization<char8_t> : Serialization_Conversion<char8_t, vint64_t> {};
|
|
|
|
template<>
|
|
struct Serialization<char16_t> : Serialization_Conversion<char16_t, vint64_t> {};
|
|
|
|
template<>
|
|
struct Serialization<char32_t> : Serialization_Conversion<char32_t, vint64_t> {};
|
|
|
|
/***********************************************************************
|
|
Serialization (floats)
|
|
***********************************************************************/
|
|
|
|
template<>
|
|
struct Serialization<double> : Serialization_POD<double> {};
|
|
|
|
template<>
|
|
struct Serialization<float> : Serialization_POD<float> {};
|
|
|
|
template<>
|
|
struct Serialization<bool> : Serialization_Conversion<bool, vint8_t, Serialization<bool>>
|
|
{
|
|
static bool ToValue(vint8_t data)
|
|
{
|
|
return data == -1;
|
|
}
|
|
|
|
static vint8_t FromValue(bool value)
|
|
{
|
|
return value ? -1 : 0;
|
|
}
|
|
};
|
|
|
|
/***********************************************************************
|
|
Serialization (enum)
|
|
***********************************************************************/
|
|
|
|
template<typename T>
|
|
requires(std::is_enum_v<T>)
|
|
struct Serialization<T> : Serialization_Conversion<T, vint64_t> {};
|
|
|
|
/***********************************************************************
|
|
Serialization (strings)
|
|
***********************************************************************/
|
|
|
|
template<>
|
|
struct Serialization<U8String>
|
|
{
|
|
template<typename TContext>
|
|
static void IO(Reader<TContext>& reader, U8String& value)
|
|
{
|
|
vint count = -1;
|
|
reader << count;
|
|
if (count > 0)
|
|
{
|
|
char8_t* buffer = new char8_t[count + 1];
|
|
MemoryWrapperStream stream(buffer, count);
|
|
reader << (IStream&)stream;
|
|
buffer[count] = 0;
|
|
value = U8String::TakeOver(buffer, count);
|
|
}
|
|
else
|
|
{
|
|
value = {};
|
|
}
|
|
}
|
|
|
|
template<typename TContext>
|
|
static void IO(Writer<TContext>& writer, U8String& value)
|
|
{
|
|
vint count = value.Length();
|
|
writer << count;
|
|
if (count > 0)
|
|
{
|
|
MemoryWrapperStream stream((void*)value.Buffer(), count);
|
|
writer << (IStream&)stream;
|
|
}
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct Serialization<WString> : Serialization_Conversion<WString, U8String, Serialization<WString>>
|
|
{
|
|
static WString ToValue(const U8String& data)
|
|
{
|
|
return u8tow(data);
|
|
}
|
|
|
|
static U8String FromValue(const WString& value)
|
|
{
|
|
return wtou8(value);
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct Serialization<U16String> : Serialization_Conversion<U16String, U8String, Serialization<U16String>>
|
|
{
|
|
static U16String ToValue(const U8String& data)
|
|
{
|
|
return u8tou16(data);
|
|
}
|
|
|
|
static U8String FromValue(const U16String& value)
|
|
{
|
|
return u16tou8(value);
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct Serialization<U32String> : Serialization_Conversion<U32String, U8String, Serialization<U32String>>
|
|
{
|
|
static U32String ToValue(const U8String& data)
|
|
{
|
|
return u8tou32(data);
|
|
}
|
|
|
|
static U8String FromValue(const U32String& value)
|
|
{
|
|
return u32tou8(value);
|
|
}
|
|
};
|
|
|
|
/***********************************************************************
|
|
Serialization (generic types)
|
|
***********************************************************************/
|
|
|
|
template<typename T>
|
|
struct Serialization<Ptr<T>>
|
|
{
|
|
template<typename TContext>
|
|
static void IO(Reader<TContext>& reader, Ptr<T>& value)
|
|
{
|
|
bool notNull = false;
|
|
reader << notNull;
|
|
if (notNull)
|
|
{
|
|
value = Ptr(new T);
|
|
Serialization<T>::IO(reader, *value.Obj());
|
|
}
|
|
else
|
|
{
|
|
value = 0;
|
|
}
|
|
}
|
|
|
|
template<typename TContext>
|
|
static void IO(Writer<TContext>& writer, Ptr<T>& value)
|
|
{
|
|
bool notNull = value;
|
|
writer << notNull;
|
|
if (notNull)
|
|
{
|
|
Serialization<T>::IO(writer, *value.Obj());
|
|
}
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
struct Serialization<Nullable<T>>
|
|
{
|
|
template<typename TContext>
|
|
static void IO(Reader<TContext>& reader, Nullable<T>& value)
|
|
{
|
|
bool notNull = false;
|
|
reader << notNull;
|
|
if (notNull)
|
|
{
|
|
T data;
|
|
Serialization<T>::IO(reader, data);
|
|
value = Nullable<T>(data);
|
|
}
|
|
else
|
|
{
|
|
value = Nullable<T>();
|
|
}
|
|
}
|
|
|
|
template<typename TContext>
|
|
static void IO(Writer<TContext>& writer, Nullable<T>& value)
|
|
{
|
|
bool notNull = value;
|
|
writer << notNull;
|
|
if (notNull)
|
|
{
|
|
T data = value.Value();
|
|
Serialization<T>::IO(writer, data);
|
|
}
|
|
}
|
|
};
|
|
|
|
/***********************************************************************
|
|
Serialization (collections)
|
|
***********************************************************************/
|
|
|
|
template<typename T>
|
|
struct Serialization<collections::List<T>>
|
|
{
|
|
template<typename TContext>
|
|
static void IO(Reader<TContext>& reader, collections::List<T>& value)
|
|
{
|
|
vint32_t count = -1;
|
|
reader << count;
|
|
value.Clear();
|
|
for (vint i = 0; i < count; i++)
|
|
{
|
|
T t;
|
|
reader << t;
|
|
value.Add(t);
|
|
}
|
|
}
|
|
|
|
template<typename TContext>
|
|
static void IO(Writer<TContext>& writer, collections::List<T>& value)
|
|
{
|
|
vint32_t count = (vint32_t)value.Count();
|
|
writer << count;
|
|
for (vint i = 0; i < count; i++)
|
|
{
|
|
writer << value[i];
|
|
}
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
struct Serialization<collections::Array<T>>
|
|
{
|
|
template<typename TContext>
|
|
static void IO(Reader<TContext>& reader, collections::Array<T>& value)
|
|
{
|
|
vint32_t count = -1;
|
|
reader << count;
|
|
value.Resize(count);
|
|
for (vint i = 0; i < count; i++)
|
|
{
|
|
reader << value[i];
|
|
}
|
|
}
|
|
|
|
template<typename TContext>
|
|
static void IO(Writer<TContext>& writer, collections::Array<T>& value)
|
|
{
|
|
vint32_t count = (vint32_t)value.Count();
|
|
writer << count;
|
|
for (vint i = 0; i < count; i++)
|
|
{
|
|
writer << value[i];
|
|
}
|
|
}
|
|
};
|
|
|
|
template<typename K, typename V>
|
|
struct Serialization<collections::Dictionary<K, V>>
|
|
{
|
|
template<typename TContext>
|
|
static void IO(Reader<TContext>& reader, collections::Dictionary<K, V>& value)
|
|
{
|
|
vint32_t count = -1;
|
|
reader << count;
|
|
value.Clear();
|
|
for (vint i = 0; i < count; i++)
|
|
{
|
|
K k;
|
|
V v;
|
|
reader << k << v;
|
|
value.Add(k, v);
|
|
}
|
|
}
|
|
|
|
template<typename TContext>
|
|
static void IO(Writer<TContext>& writer, collections::Dictionary<K, V>& value)
|
|
{
|
|
vint32_t count = (vint32_t)value.Count();
|
|
writer << count;
|
|
for (vint i = 0; i < count; i++)
|
|
{
|
|
K k = value.Keys()[i];
|
|
V v = value.Values()[i];
|
|
writer << k << v;
|
|
}
|
|
}
|
|
};
|
|
|
|
template<typename K, typename V>
|
|
struct Serialization<collections::Group<K, V>>
|
|
{
|
|
template<typename TContext>
|
|
static void IO(Reader<TContext>& reader, collections::Group<K, V>& value)
|
|
{
|
|
vint32_t count = -1;
|
|
reader << count;
|
|
value.Clear();
|
|
for (vint i = 0; i < count; i++)
|
|
{
|
|
K k;
|
|
collections::List<V> v;
|
|
reader << k << v;
|
|
for (vint j = 0; j < v.Count(); j++)
|
|
{
|
|
value.Add(k, v[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename TContext>
|
|
static void IO(Writer<TContext>& writer, collections::Group<K, V>& value)
|
|
{
|
|
vint32_t count = (vint32_t)value.Count();
|
|
writer << count;
|
|
for (vint i = 0; i < count; i++)
|
|
{
|
|
K k = value.Keys()[i];
|
|
collections::List<V>& v = const_cast<collections::List<V>&>(value.GetByIndex(i));
|
|
writer << k << v;
|
|
}
|
|
}
|
|
};
|
|
|
|
/***********************************************************************
|
|
Serialization (MISC)
|
|
***********************************************************************/
|
|
|
|
template<>
|
|
struct Serialization<stream::IStream>
|
|
{
|
|
template<typename TContext>
|
|
static void IO(Reader<TContext>& reader, stream::IStream& value)
|
|
{
|
|
vint32_t count = 0;
|
|
reader.input.Read(&count, sizeof(count));
|
|
|
|
if (count > 0)
|
|
{
|
|
vint length = 0;
|
|
collections::Array<vuint8_t> buffer(count);
|
|
value.SeekFromBegin(0);
|
|
length = reader.input.Read(&buffer[0], count);
|
|
if (length != count)
|
|
{
|
|
CHECK_FAIL(L"Deserialization failed.");
|
|
}
|
|
length = value.Write(&buffer[0], count);
|
|
if (length != count)
|
|
{
|
|
CHECK_FAIL(L"Deserialization failed.");
|
|
}
|
|
value.SeekFromBegin(0);
|
|
}
|
|
}
|
|
|
|
template<typename TContext>
|
|
static void IO(Writer<TContext>& writer, stream::IStream& value)
|
|
{
|
|
vint32_t count = (vint32_t)value.Size();
|
|
writer.output.Write(&count, sizeof(count));
|
|
|
|
if (count > 0)
|
|
{
|
|
vint length = 0;
|
|
collections::Array<vuint8_t> buffer(count);
|
|
value.SeekFromBegin(0);
|
|
length = value.Read(&buffer[0], count);
|
|
if (length != count)
|
|
{
|
|
CHECK_FAIL(L"Serialization failed.");
|
|
}
|
|
length = writer.output.Write(&buffer[0], count);
|
|
if (length != count)
|
|
{
|
|
CHECK_FAIL(L"Serialization failed.");
|
|
}
|
|
value.SeekFromBegin(0);
|
|
}
|
|
}
|
|
};
|
|
|
|
/***********************************************************************
|
|
Serialization (macros)
|
|
***********************************************************************/
|
|
|
|
#define BEGIN_SERIALIZATION(TYPE)\
|
|
template<>\
|
|
struct Serialization<TYPE>\
|
|
{\
|
|
template<typename TIO>\
|
|
static void IO(TIO& op, TYPE& value)\
|
|
{\
|
|
op\
|
|
|
|
#define SERIALIZE(FIELD)\
|
|
<< value.FIELD\
|
|
|
|
#define END_SERIALIZATION\
|
|
;\
|
|
}\
|
|
};\
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|