topic "U++ Core value types tutorial";
[2 $$0,0#00000000000000000000000000000000:Default]
[l288;i1120;a17;O9;~~~.1408;2 $$1,0#10431211400427159095818037425705:param]
[a83;*R6 $$2,5#31310162474203024125188417583966:caption]
[b83;*4 $$3,5#07864147445237544204411237157677:title]
[i288;O9;C2 $$4,6#40027414424643823182269349404212:item]
[b42;a42;2 $$5,5#45413000475342174754091244180557:text]
[l288;b17;a17;2 $$6,6#27521748481378242620020725143825:desc]
[l321;t246;C@5;1 $$7,7#20902679421464641399138805415013:code]
[b2503;2 $$8,0#65142375456100023862071332075487:separator]
[*@(0.0.255)2 $$9,0#83433469410354161042741608181528:base]
[t4167;C2 $$10,0#37138531426314131251341829483380:class]
[l288;a17;*1 $$11,11#70004532496200323422659154056402:requirement]
[i417;b42;a42;O9;~~~.416;2 $$12,12#10566046415157235020018451313112:tparam]
[b167;C2 $$13,13#92430459443460461911108080531343:item1]
[i288;a42;O9;C2 $$14,14#77422149456609303542238260500223:item2]
[*@2$(0.128.128)2 $$15,15#34511555403152284025741354420178:NewsDate]
[l321;*C$7;2 $$16,0#03451589433145915344929335295360:result]
[l321;b83;a83;*C$7;2 $$17,17#07531550463529505371228428965313:result`-line]
[l160;t4167;*C+117 $$18,5#88603949442205825958800053222425:package`-title]
[2 $$19,0#53580023442335529039900623488521:gap]
[t4167;C2 $$20,20#70211524482531209251820423858195:class`-nested]
[b50;2 $$21,21#03324558446220344731010354752573:Par]
[{_}%EN-US 
[s2; U`+`+ Core value types tutorial&]
[s3; 1. String&]
[s5; String is a value type useful for storing text or binary data. 
Content of String can be also obtained in form zero terminated 
const char `*ptr (valid till the next mutating operation only.&]
[s5; You can assign a C string literal to String&]
[s7; &]
[s7; String a;&]
[s7; a `= `"Hello`";&]
[s7; &]
[s16; a `= Hello&]
[s7; &]
[s7; &]
[s5; concatenate with another String or literal&]
[s7; &]
[s7; a `= a `+ `" world`";&]
[s7; &]
[s16; a `= Hello world&]
[s7; &]
[s7; &]
[s5; or single character or specified number of characters from another 
String or literal&]
[s7; &]
[s7; a.Cat(`'!`');&]
[s7; &]
[s16; a `= Hello world!&]
[s7; &]
[s7; a.Cat(`"ABCDEFGHIJKLM`", 3);&]
[s7; &]
[s16; a `= Hello world!ABC&]
[s7; &]
[s7; &]
[s5; Clear method empties the String&]
[s7; &]
[s7; a.Clear();&]
[s7; &]
[s7; &]
[s5; You can use operator<< to append to existing String. Note that 
this is more efficient form than operator`+ as String is not 
required to be assigned a temporary. Also, U`+`+ provides extensible 
framework for converting values to String&]
[s7; &]
[s7; for(int i `= 0; i < 10; i`+`+)&]
[s7; -|a << i << `", `";&]
[s7; &]
[s16; a `= 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, &]
[s16; &]
[s16; &]
[s5; Sometimes is is useful to use operator<< to produce a temporary 
String value (e.g. as real argument to function call).&]
[s16; &]
[s7; String().Cat() << `"Number is `" << 123 << `".`"&]
[s7; &]
[s5; Note: This strange special Cat method is needed because C`+`+ 
does not allow non`-cont references to temporary objects.&]
[s7; &]
[s16; Number is 123.&]
[s7; &]
[s7; &]
[s5; String provides methods for obtaining character count, inserting 
characters into String or removing them&]
[s7; &]
[s7; a `= `"0123456789`";&]
[s7; &]
[s16; a.GetLength() `= 10&]
[s7; &]
[s7; a.Insert(6, `"<inserted>`");&]
[s7; &]
[s16; a `= 012345<inserted>6789&]
[s7; &]
[s7; a.Remove(2, 2);&]
[s7; &]
[s16; a `= 0145<inserted>6789&]
[s7; &]
[s7; &]
[s5; as well as a couple of searching and comparing methods&]
[s7; &]
[s7; a.Find(`'e`')&]
[s7; &]
[s16; a.Find(`'e`') `= 8&]
[s7; &]
[s7; a.ReverseFind(`'e`')&]
[s7; &]
[s16; a.ReverseFind(`'e`') `= 11&]
[s16; &]
[s7; a.StartsWith(`"ABC`")&]
[s7; &]
[s16; a.StartsWith(`"ABC`") `= false&]
[s7; &]
[s7; a.EndsWith(`"KLM`")&]
[s7; &]
[s16; a.EndsWith(`"KLM`") `= false&]
[s7; &]
[s7; a.Find(`"ted`")&]
[s7; &]
[s16; a.Find(`"ted`") `= 10&]
[s7; &]
[s7; &]
[s5; You can get slice of String using Mid method; with single parameter 
it provides slice to the end of String&]
[s7; &]
[s7; a.Mid(3, 3)&]
[s7; &]
[s16; a.Mid(3, 3) `= 5<i&]
[s7; &]
[s7; a.Mid(3)&]
[s7; &]
[s16; a.Mid(3) `= 5<inserted>6789&]
[s7; &]
[s7; &]
[s5; You can also decrease the length of String using Trim&]
[s7; &]
[s7; a.Trim(4);&]
[s7; &]
[s16; a `= 0145&]
[s7; &]
[s7; &]
[s5; You can obtain int values of individual characters using operator`[`]&]
[s7; &]
[s7; a`[0`]&]
[s7; &]
[s16; a`[0`] `= 48&]
[s7; &]
[s7; &]
[s5; or the value of first character using operator`* (note that 
if GetLengt() `=`= 0, this will return zero terminator)&]
[s7; &]
[s7; -|DUMP(`*a);&]
[s7; &]
[s16; `*a `= 48&]
[s7; &]
[s0; &]
[s3; 2. StringBuffer&]
[s5; If you need a direct write access to String`'s C`-string character 
buffer, you can use complementary StringBuffer class. One of 
reasons to do so is when you have to deal with some C`-API functions&]
[s7; void CApiFunction(char `*c)&]
[s7; `{&]
[s7; -|strcpy(c, `"Hello`");&]
[s7; `}&]
[s7; &]
[s7; ..........&]
[s7; &]
[s7; [* -|StringBuffer] b;&]
[s7; -|b.[* SetLength](200);&]
[s7; -|CApiFunction(b);&]
[s7; -|b.[* Strlen]();&]
[s7; -|String x [* `=] b;&]
[s7; &]
[s16; x `= Hello&]
[s7; &]
[s5; In this case, SetLength creates a C array of 200 characters. 
You can then call C`-API function. Later you set the real length 
using Strlen `- this function performs strlen of buffer and sets 
the length accordingly. Later you simply assign the StringBuffer 
to String. Note that for performance reasons, this operation 
clears the StringBuffer content (operation is fast and does not 
depend on the number of characters).&]
[s5; Another usage scenario of StringBuffer is about altering existing 
String&]
[s7; -|b `= x;&]
[s7; -|b`[1`] `= `'a`';&]
[s7; -|x `= b;&]
[s7; &]
[s16; x `= Hallo&]
[s16; &]
[s5; Similar to assigning StringBuffer to String, assigning String 
to StringBuffer clears the source String.&]
[s5; StringBuffer also provides appending operations:&]
[s7; -|b `= x;&]
[s7; -|b.Cat(`'!`');&]
[s7; -|x `= b;&]
[s7; &]
[s16; x `= Hallo!&]
[s16; &]
[s5; Note that sometimes when creating some String from a lot of 
single characters, using StringBuffer for the operation is slightly 
faster then using String directly.&]
[s5; &]
[s3; 3. WString&]
[s5; String works with 8 bit characters. For 16`-bit character encoding 
use WString. Both classes are closely related and share most 
of interface methods. U`+`+ also provides conversions between 
String and WString and you can also use 8 bit string literals 
with WString. Conversion is ruled by current [*/ default character 
set][/ . ]Default value of default character set is CHARSET`_UTF8.&]
[s7; &]
[s7; -|WString x `= `"characters 280`-300: `";&]
[s7; -|for(int i `= 280; i < 300; i`+`+)&]
[s7; -|-|x.Cat(i);&]
[s7; &]
[s16; x `= characters 280`-300: ĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪī&]
[s7; &]
[s7; -|String y `= x.ToString();&]
[s7; -|DUMP(y);&]
[s7; &]
[s16; y `= characters 280`-300: ĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪī&]
[s7; &]
[s7; -|y.Cat(`" (appended)`");&]
[s7; -|x `= y.ToWString();&]
[s7; &]
[s16; x `= characters 280`-300: ĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪī 
(appended)-|&]
[s7; &]
[s5; [/ (Note: y content is displayed as result of conversion from utf`-8 
encoded data)]&]
[s5; &]
[s3; 4. Date and Time&]
[s5; To represent date and time, U`+`+ provides Date and Time concrete 
types.&]
[s7; &]
[s7; -|Date date `= GetSysDate();&]
[s0; &]
[s16; date `= 01/21/2007&]
[s0; &]
[s0; All data members of Date structure are public:&]
[s0; &]
[s16; date.year `= 2007&]
[s16; date.month `= 1&]
[s16; date.day `= 21&]
[s0; &]
[s0; Dates can be compared:&]
[s0; &]
[s16; date > Date(1970, 1, 1) `= true&]
[s0; &]
[s0; Adding a number to Date adds a number of days to it:&]
[s0; &]
[s16; date `+ 1 `= 01/22/2007&]
[s0; &]
[s0; Subtraction of dates yields a number of days between them:&]
[s0; &]
[s16; date `- Date(1970, 1, 1) `= 13534&]
[s0; &]
[s0; U`+`+ defines the beginning and the end of era, most algorithms 
can safely assume that as minimal and maximal values Date can 
represent:&]
[s0; &]
[s16; Date`::Low() `= 01/01/`-4000&]
[s16; Date`::High() `= 01/01/4000&]
[s0; -|&]
[s0; &]
[s0; Time is [/ derived] from Date, adding members to represent time:&]
[s0; &]
[s7; -|Time time `= GetSysTime();&]
[s0; &]
[s16; time `= 01/21/2007 23:28:59&]
[s16; (Date`&)time `= 01/21/2007&]
[s16; (int)time.hour `= 23&]
[s16; (int)time.minute `= 28&]
[s16; (int)time.second `= 59&]
[s0; &]
[s0; Times can be compared:&]
[s0; &]
[s16; time > Time(1970, 0, 0) `= true&]
[s0; &]
[s0; Warning: As Time is derived from the Date, most operations automatically 
convert Time back to Date. You have to use ToTime conversion 
function to convert Date to Time:&]
[s0; &]
[s16; time > date `= false&]
[s16; time > ToTime(date) `= true&]
[s16; &]
[s0; &]
[s0; Like Date, Time supports add and subtract operations, but numbers 
represent seconds (using int64 datatype):&]
[s0; &]
[s16; time `+ 1 `= 01/21/2007 23:29:00&]
[s16; time `+ 24 `* 3600 `= 01/22/2007 23:28:59&]
[s16; time `- date `= 0&]
[s16; time `- ToTime(date) `= 84539&]
[s0; &]
[s0; Time also defines era limits:&]
[s0; &]
[s16; Time`::Low() `= 01/01/`-4000 00:00:00&]
[s16; Time`::High() `= 01/01/4000 00:00:00&]
[s5;/ &]
[s3; 5. AsString, ToString and operator<<&]
[s5; U`+`+ Core provides simple yet effective standard schema for 
converting values to default textual form.&]
[s5; System is based on the combination of template functions [/ (following 
code is part of U`+`+ headers)]:&]
[s7; &]
[s7; template <class T>&]
[s7; inline String AsString(const T`& x)&]
[s7; `{&]
[s7; -|return x.ToString();&]
[s7; `}&]
[s7; &]
[s7; template <class T>&]
[s7; inline Stream`& operator<<(Stream`& s, const T`& x)&]
[s7; `{&]
[s7; -|s << AsString(x);&]
[s7; -|return s;&]
[s7; `}&]
[s7; &]
[s7; template <class T>&]
[s7; inline String`& operator<<(String`& s, const T`& x)&]
[s7; `{&]
[s7; -|s.Cat(AsString(x));&]
[s7; -|return s;&]
[s7; `}&]
[s7; &]
[s7; &]
[s5; Client types have to either define String [*/ ToString] method 
(usually more convenient) or specialize [*/ AsString] template. 
Such types can be appended to Streams or Strings using [*/ operator<<]. 
Of course, U`+`+ value types and primitive types have required 
items predefined by U`+`+:&]
[s7; &]
[s7; -|FileOut fout(ConfigFile(`"test.txt`"));&]
[s7; -|String  sout;&]
[s7; -|&]
[s7; -|fout << 1.23 << `' `' << GetSysDate() << `' `' << GetSysTime();&]
[s7; -|sout << 1.23 << `' `' << GetSysDate() << `' `' << GetSysTime();&]
[s7; &]
[s16; sout `= 1.23 01/22/2007 01/22/2007 17:58:58&]
[s0; &]
[s5; Getting client types involved into this schema is not too difficult 
(example shows both methods):&]
[s7; &]
[s7; struct BinFoo `{&]
[s7; -|int x;&]
[s7; -|&]
[s7; -|String [* ToString]() const   `{ return FormatIntBase(x, 2); 
`}&]
[s7; -|&]
[s7; -|BinFoo(int x) : x(x) `{`}&]
[s7; `};&]
[s7; &]
[s7; struct RomanFoo `{&]
[s7; -|int x;&]
[s7; -|&]
[s7; -|RomanFoo(int x) : x(x) `{`}&]
[s7; `};&]
[s7; &]
[s7; namespace Upp `{&]
[s7; template <>&]
[s7; String Upp`::[* AsString](const RomanFoo`& a) `{ return FormatIntRoman(a.x); 
`}&]
[s7; `};&]
[s7; .......&]
[s7; &]
[s7; -|sout << BinFoo(30) << `' `' << RomanFoo(30);&]
[s7; &]
[s7; &]
[s16; sout `= 11110 xxx&]
[s5; &]
[s3; 6. Value&]
[s5; U`+`+ provides one special value type, Value, that can be used 
to store and retrieve other values.&]
[s7; &]
[s7; -|Value a `= 1;&]
[s7; -|Value b `= 2.34;&]
[s7; -|Value c `= GetSysDate();&]
[s7; -|Value d `= `"hello`";&]
[s7; &]
[s5; Usually, value types define typecast operator to Value and constructor 
from Value, so that interaction is for the most part seamless:&]
[s7; &]
[s7; -|int x `= a;&]
[s7; -|double y `= b;&]
[s7; -|Date z `= c;&]
[s7; -|String s `= d;&]
[s7; &]
[s16; x `= 1&]
[s16; y `= 2.34&]
[s16; z `= 01/24/2007&]
[s16; s `= hello&]
[s0; &]
[s0; As for primitive types, Value seamlessly works with [* int], [* int64], 
[* bool] and [* double].&]
[s0; &]
[s0; Casting Value to a type that it does not contain causes runtime 
error. On the other hand, conversion between related types is 
possible:&]
[s0; &]
[s7; &]
[s7; -|double i `= a;&]
[s7; -|int j `= b;&]
[s7; -|Time k `= c;&]
[s7; -|WString t `= d;&]
[s7; &]
[s16; i `= 1&]
[s16; j `= 2&]
[s16; k `= 01/24/2007&]
[s16; t `= hello&]
[s0; &]
[s0; To determine type of value stored in Value, you can use [* Is] 
method:&]
[s0; &]
[s16; a.Is<int>() `= true&]
[s16; a.Is<double>() `= false&]
[s16; b.Is<double>() `= true&]
[s16; c.Is<int>() `= false&]
[s16; c.Is<Date>() `= true&]
[s16; d.Is<String>() `= true&]
[s0; &]
[s0; Note that Is tests for absolute type match, not for compatible 
types. For that reason, for widely used compatible types utility 
functions are defined:&]
[s0; &]
[s16; &]
[s16; IsNumber(a) `= true&]
[s16; IsNumber(b) `= true&]
[s16; IsDateTime(c) `= true&]
[s16; IsString(d) `= true&]
[s5; &]
[s3; 7. Null&]
[s5; U`+`+ defines a special Null constant to represent an empty 
value. This constant is convertible to many value types including 
primitive types double, int and int64 (defined as lowest number 
the type can represent). If type supports ordering (<, >), all 
values of the type are greater than Null value. To test whether 
a value is empty, use IsNull function.&]
[s7; &]
[s7; -|int x `= Null;&]
[s7; -|int y `= 120;&]
[s7; -|Date d `= Null;&]
[s7; -|Date e `= GetSysDate();&]
[s7; &]
[s16; IsNull(x) `= true&]
[s16; IsNull(y) `= false&]
[s16; IsNull(d) `= true&]
[s16; e > d `= true&]
[s0; &]
[s0; C`+`+ language note: Null is the only instance of Nuller type. 
Assigning Null to primitive types is achieved by cast operators 
of Nuller, other types can do it using constructor from Nuller.&]
[s0; &]
[s0; As a special case, if Value contains Null, it is convertible 
to any value type that can contain Null:&]
[s0; &]
[s7; &]
[s7; -|Value v `= x;&]
[s7; -|e `= v;&]
[s7; &]
[s16; IsNull(e) `= true&]
[s5; &]
[s3; 8. Client types and Value, RawValue, RichValue&]
[s5; There are two Value compatibility levels. The simple one, [*/ RawValue], 
has little requirements for the type used `- only copy constructor 
and assignment operator are required:&]
[s7; &]
[s7; struct RawFoo `{&]
[s7; -|String x;&]
[s7; `};&]
[s7; &]
[s7; &]
[s0; (int this case, default copy constructor and assignment operator 
are provided by compiler).&]
[s7; &]
[s7; -|RawFoo h;&]
[s7; -|h.x `= `"hello`";&]
[s7; -|Value q `= RawToValue(h);&]
[s7; &]
[s16; q.Is<Foo>() `= true&]
[s16; q.To<Foo>().x `= `"hello`"&]
[s7; &]
[s0; [*/ RichValue] level Values provide more operations for Value 
`- equality test, IsNull test, hashing, conversion to text and 
serialization. In order to make serialization work, type must 
also have assigned an integer id (client types should use ids 
in range 10000..20000). Type can provide the support for these 
operations via template function specializations or (perhaps 
more convenient) using defined methods and inheriting from ValueType 
base class template:&]
[s7; &]
[s7; struct Foo : ValueType<Foo, 10010> `{&]
[s7; -|int x;&]
[s7; -|&]
[s7; -|Foo(const Nuller`&)                  `{ x `= Null; `}&]
[s7; -|Foo(int x) : x(x) `{`}&]
[s7; -|Foo() `{`}&]
[s7; &]
[s7; -|String ToString() const             `{ return AsString(x); 
`}&]
[s7; -|unsigned GetHashValue() const       `{ return x; `}&]
[s7; -|void Serialize(Stream`& s)           `{ s % x; `}&]
[s7; -|bool operator`=`=(const Foo`& b) const `{ return x `=`= b.x; 
`}&]
[s7; -|bool IsNullInstance() const         `{ return IsNull(x); `}-|&]
[s7; `};&]
[s7; &]
[s7; INITBLOCK `{&]
[s7; -|Value`::Register<Foo>();&]
[s7; `}&]
[s7; .......&]
[s7; &]
[s7; -|Value a `= [* RichToValue](Foo(54321));&]
[s7; -|Value b `= RichToValue(Foo(54321));&]
[s7; &]
[s16; (a `=`= b) `= true&]
[s16; IsNull(a) `= false&]
[s16; v.Get<Foo>() `= 54321&]
[s7; &]
[s7; -|String s `= StoreAsString(a);&]
[s7; -|LoadFromString(v, s);&]
[s7; &]
[s16; v.Get<Foo>() `= 54321&]
[s0; &]
[s0; To avoid RichToValue and ValueTo calls, the client type can 
also provide constructor from Value and cast operator to Value:&]
[s0; &]
[s7; struct Foo : ValueType<Foo, 10010> `{&]
[s7; -|int x;&]
[s7; -|&]
[s7; ......&]
[s7; -|&]
[s7; -|operator Value()    `{ return RichToValue(`*this); `}&]
[s7; -|Foo(const Value`& v) `{ `*this `= v.Get<Foo>(); `}&]
[s7; `};&]
[s7; &]
[s7; ......&]
[s7; &]
[s7; -|Value c `= Foo(321);&]
[s7; -|Foo x `= c;&]
[s7; &]
[s16; x `= 123&]
[s5; &]
[s3; 9. CombineHash&]
[s5; To simplify providing of high quality hash codes for composite 
types, U`+`+ provides CombineHash utility class. This class uses 
GetHashValue function to gather hash codes of all values and 
combines them to provide final hash value for composite type:&]
[s7; &]
[s7; struct Foo `{&]
[s7; -|String a;&]
[s7; -|int    b;&]
[s7; -|&]
[s7; -|unsigned [* GetHashValue]() const `{ return [* CombineHash](a, 
b); `}&]
[s7; `};&]
[s7; &]
[s0; Note that GetHashValue is defined as function template that 
calls GetHashValue method of its argument, therefore defining 
GetHashValue method defines GetHashValue function too.&]
[s7; &]
[s7; -|Foo x;&]
[s7; -|x.a `= `"world`";&]
[s7; -|x.b `= 22;&]
[s7; &]
[s16; GetHashValue(x) `= 4272824901&]
[s16; &]
[s7; -|x.a << `'!`';&]
[s7; &]
[s16; GetHashValue(x) `= 3378606405&]
[s7; &]
[s0; &]
[s0; &]
[s0; &]
[s0; [/ (to be continued)]]]