[ $$0,0#00000000000000000000000000000000:Default]
[a83;*R6 $$1,3#31310162474203024125188417583966:caption]
[H4;b83;*4 $$2,3#07864147445237544204411237157677:title]
[b42;a42;ph2 $$3,3#45413000475342174754091244180557:text]
[l321;C@5;1 $$4,4#20902679421464641399138805415013:code]
[l321;b83;a83;*C$7;2 $$5,5#07531550463529505371228428965313:result`-line]
[l321;*C$7;2 $$6,6#03451589433145915344929335295360:result]
[{_}%EN-US 
[s1; U`+`+ Containers Tutorial&]
[s2; 1. Vector basics&]
[s3; Let us start with a simple [* Vector] of ints&]
[s4; -|[* Vector<int>] v;&]
[s3; You can add elements to the Vector as parameters of the [* Add] 
method&]
[s4; -|v.[* Add](1);&]
[s4; -|v.Add(2);&]
[s4; -|v.Add(3);&]
[s3; To iterate Vector you can use indices&]
[s4; -|for(int i `= 0; i < v.[* GetCount](); i`+`+)&]
[s4; -|-|LOG(v[* `[]i[* `]]);&]
[s3; Alternative, U`+`+ also provides standard C`+`+ begin/end interface&]
[s4; -|for(auto q `= v.[* begin](), e `= v.[* end](); q !`= e; q`+`+)&]
[s4; -|-|LOG([* `*]q);&]
[s3; or with C`+`+11 range`-for syntax:&]
[s4; -|for(const auto`& q : v)&]
[s4; -|-|LOG(q);&]
[s3;/ &]
[s3; [/ Note: LOG is diagnostics macro that outputs its argument to 
the .log file in debug mode. Another similar macros we will use 
in this tutorial are DUMP (similar to the LOG, but dumps the 
source expression too) and DUMPC (dumps the content of the container).]&]
[s3;/ &]
[s2; 2. Vector operations&]
[s3; You can [* Insert] or [* Remove] elements at random positions of 
Vector&]
[s4; -|Vector<int> v;&]
[s4; -|v.Add(1);&]
[s4; -|v.Add(2);&]
[s4; -|&]
[s4; -|v.[* Insert](1, 10);&]
[s5;  v `= `{ 1, 10, 2 `}&]
[s4; -|v.[* Remove](0);&]
[s5;  v `= `{ 10, 2 `}&]
[s3; [* At] method returns element at specified position ensuring that 
such a position exists. If there is not enough elements in Vector, 
required number of elements is added. If second parameter of 
At is present, newly added elements are initialized to this value. 
As an example, we will create distribution of RandomValue with 
unknown maximal value&]
[s4; &]
[s4; -|v.Clear();&]
[s4; -|for(int i `= 0; i < 10000; i`+`+)&]
[s4; -|-|v.[* At](RandomValue(), 0)`+`+;&]
[s5;  v `= `{ 958, 998, 983, 1012, 1013, 1050, 989, 998, 1007, 992 
`}&]
[s3; You can apply algorithms on containers, e.g. [* Sort]&]
[s4; -|[* Sort](v);&]
[s5;  v `= `{ 958, 983, 989, 992, 998, 998, 1007, 1012, 1013, 1050 
`}&]
[s3; &]
[s2; 3. Transfer issues&]
[s3; Often you need to pass content of one container to another of 
the same type. NTL containers always support [^topic`:`/`/Core`/srcdoc`/pick`_`$en`-us^ p
ick semantics] (equivalent of std`::move), and, depending on type 
stored, also might support [^topic`:`/`/Core`/srcdoc`/pick`_`$en`-us^ clone 
sematics]. When transfering the value, you have to explicitly 
specify which one to use:&]
[s4; -|Vector<int> v;&]
[s4; -|v.Add(1);&]
[s4; -|v.Add(2);&]
[s4; &]
[s4; -|Vector<int> v1 [* `=] pick(v);&]
[s3; now source Vector [C v] is destroyed `- picked `- and you can 
no longer access its content. This behaviour has many advantages. 
First, it is consistently fast and in most cases, transfer of 
value instead of full copy is exactly what you need. Second, 
NTL containers can store elements that lack copy operation `- 
in that case, pick transfer is the only option anyway.&]
[s3; If you really need to preserve value of source (and elements 
support deep copy operation), you can use [^topic`:`/`/Core`/srcdoc`/pick`_`$en`-us^ c
lone]&]
[s4; -|v [* `=] clone(v1);&]
[s3; &]
[s2; 4. Client types&]
[s3; So far we were using int as type of elements. In order to store 
client defined types into the Vector (and the Vector [^topic`:`/`/Core`/src`/Overview`$en`-us^ f
lavor]) the type must satisfy [^topic`:`/`/Core`/src`/Moveable`$en`-us^ moveable] 
requirement `- in short, it must not contain back`-pointers nor 
virtual methods. Type must be marked as moveable in order to 
define interface contract using&]
[s4; -|struct Distribution : [* Moveable]<Distribution> `{&]
[s4; -|-|String      text;&]
[s4; -|-|Vector<int> data;&]
[s4; &]
[s4; -|-|rval`_default(Distribution);&]
[s4; -|-|Distribution() `{`}&]
[s4; -|`};&]
[s3; Note that rval`_default macro is helper to restore default deleted 
r`-value constructor in C`+`+11 and default constructor is also 
default deleted in C`+`+11.&]
[s3; Now to add Distribution elements you cannot use Add with parameter, 
because it requires elements to have default deep`-copy constructor 
`- and Distribution does not have one, as Vector<int> has default 
pick`-constructor, so Distribution itself has pick`-constructor. 
It would no be a good idea either, because deep`-copy would involve 
 expensive copying of inner Vector.&]
[s3; Instead, [* Add] without parameters has to be used `- it default 
constructs (that is cheap) element in Vector and returns reference 
to it&]
[s4; -|Vector<Distribution> dist;&]
[s4; -|for(int n `= 5; n <`= 10; n`+`+) `{&]
[s4; -|-|Distribution`& d `= dist.[* Add]();&]
[s4; -|-|d.text << `"Test `" << n;&]
[s4; -|-|for(int i `= 0; i < 10000; i`+`+)&]
[s4; -|-|-|d.data.At(rand() % n, 0)`+`+;&]
[s4; -|`}&]
[s4; &]
[s6;  Test 5: `{ 2018, 1992, 2025, 1988, 1977 `}&]
[s6;  Test 6: `{ 1670, 1682, 1668, 1658, 1646, 1676 `}&]
[s6;  Test 7: `{ 1444, 1406, 1419, 1493, 1370, 1418, 1450 `}&]
[s6;  Test 8: `{ 1236, 1199, 1245, 1273, 1279, 1302, 1250, 1216 `}&]
[s6;  Test 9: `{ 1115, 1111, 1100, 1122, 1192, 1102, 1089, 1064, 1105 
`}&]
[s6;  Test 10: `{ 969, 956, 1002, 1023, 1006, 994, 1066, 1022, 929, 
1033 `}&]
[s3; Another possibility is to use AddPick method, which uses pick`-constructor 
instead of deep`-copy constructor. E.g. Distribution elements 
might be generated by some function &]
[s4; -|Distribution CreateDist(int n);&]
[s3; and code for adding such elements to Vector then looks like&]
[s4; -|for(n `= 5; n <`= 10; n`+`+)&]
[s4; -|-|dist.[* AddPick](CreateDist(n));&]
[s3; alternatively, you can use default`-constructed variant too&]
[s4; -|-|dist.Add() `= CreateDist(); // alternative&]
[s3; &]
[s2; 5. Array flavor&]
[s3; If elements do not satisfy requirements for Vector flavor, they 
can still be stored in Array flavor. Another reason for using 
Array is need for referencing elements `- Array flavor never 
invalidates references or pointers to them.&]
[s3; Example of elements that cannot be stored in Vector flavor are 
STL containers (STL does not specify the NTL flavor for obvious 
reasons):&]
[s4; -|[* Array]< std`::list<int> > al;&]
[s4; -|for(int i `= 0; i < 4; i`+`+) `{&]
[s4; -|-|std`::list<int>`& l `= al.Add();&]
[s4; -|-|for(int q `= 0; q < i; q`+`+)&]
[s4; -|-|-|l.push`_back(q);&]
[s4; -|`}&]
[s3; &]
[s2; 6. Polymorphic Array&]
[s3; Array can even be used for storing polymorphic elements &]
[s4; struct Number `{&]
[s4; -|virtual double Get() const `= 0;&]
[s4; &]
[s4; -|String ToString() const `{ return AsString(Get()); `}&]
[s4; -|&]
[s4; -|virtual `~Number() `{`}&]
[s4; `};&]
[s4; &]
[s4; struct Integer : public Number `{&]
[s4; -|int n;&]
[s4; -|virtual double Get() const `{ return n; `}&]
[s4; &]
[s4; -|Integer() `{`}&]
[s4; `};&]
[s4; &]
[s4; struct Double : public Number `{&]
[s4; -|double n;&]
[s4; -|virtual double Get() const `{ return n; `}&]
[s4; &]
[s4; -|Double() `{`}&]
[s4; `};&]
[s4; &]
[s4; bool operator<(const Number`& a, const Number`& b)&]
[s4; `{&]
[s4; -|return a.Get() < b.Get();&]
[s4; `}&]
[s4; &]
[s3; In this case, elements are added using Add with pointer to base 
element type parameter. Do not be confused by new and pointer, 
Array takes ownership of passed object and  behaves like container 
of base type elements&]
[s4; -|Array<Number> num;&]
[s4; -|num.Create<Double>().n `= 15.5;&]
[s4; -|num.Create<Integer>().n `= 3;&]
[s5;  num `= `{ 15.5, 3 `}&]
[s3; Thanks to well defined algorithm requirements, you can e.g. 
directly apply Sort on such Array&]
[s4; -|bool operator<(const Number`& a, const Number`& b)&]
[s4; -|`{&]
[s4; -|-|return a.Get() < b.Get();&]
[s4; -|`}&]
[s4; &]
[s4; .......&]
[s4; &]
[s4; -|Sort(num);&]
[s5;  num `= `{ 3, 15.5 `}&]
[s3; &]
[s2; 7. Bidirectional containers&]
[s3; Vector and Array containers allow fast adding and removing elements 
at the end of sequence. Sometimes, same is needed at begin of 
sequence too (usually to support FIFO like operations). In such 
case, BiVector and BiArray should be used&]
[s4; -|BiVector<int> n;&]
[s4; -|n.[* AddHead](1);&]
[s4; -|n.[* AddTail](2);&]
[s4; -|n.AddHead(3);&]
[s4; -|n.AddTail(4);&]
[s5;  n `= `{ 3, 1, 2, 4 `}&]
[s4; -|n.[* DropHead]();&]
[s5;  n `= `{ 1, 2, 4 `}&]
[s4; -|n.[* DropTail]();&]
[s5;  n `= `{ 1, 2 `}&]
[s4; -|BiArray<Number> num;&]
[s4; -|num.CreateHead<Integer>().n `= 3;&]
[s4; -|num.CreateTail<Double>().n `= 15.5;&]
[s4; -|num.CreateHead<Double>().n `= 2.23;&]
[s4; -|num.CreateTail<Integer>().n `= 2;&]
[s5;  num `= `{ 2.23, 3, 15.5, 2 `}&]
[s3; &]
[s2; 8. Index&]
[s3; Index is a container very similar to the plain Vector (it is 
random access array of elements with fast addition at the end) 
with one unique feature `- it is able to fast retrieve position 
of element with required value using [* Find] method&]
[s4; -|[* Index]<String> ndx;&]
[s4; -|ndx.[* Add](`"alfa`");&]
[s4; -|ndx.Add(`"beta`");&]
[s4; -|ndx.Add(`"gamma`");&]
[s4; -|ndx.Add(`"delta`");&]
[s4; -|ndx.Add(`"kappa`");&]
[s5;  ndx `= `{ alfa, beta, gamma, delta, kappa `}&]
[s4; -|DUMP(ndx.[* Find](`"beta`"));&]
[s5;  ndx.Find(`"beta`") `= 1&]
[s3; If element is not present in Index, Find returns a negative 
value&]
[s4; -|DUMP(ndx.Find(`"something`"));&]
[s5;  ndx.Find(`"something`") `= `-1&]
[s3; Any element can be replaced using [* Set] method&]
[s4; -|ndx.[* Set](0, `"delta`");&]
[s5;  ndx `= `{ delta, beta, gamma, delta, kappa `}&]
[s3; If there are more elements with the same value, they can be 
iterated using [* FindNext] method&]
[s4; -|int fi `= ndx.Find(`"delta`");&]
[s4; -|while(fi >`= 0) `{&]
[s4; -|-|DUMP(fi);&]
[s4; -|-|fi `= ndx.[* FindNext](fi);&]
[s4; -|`}&]
[s4; -|cout << `'n`';&]
[s5;  0 3-|&]
[s3; [* FindAdd] method retrieves position of element like Find, but 
if element is not present in Index, it is added&]
[s4; -|DUMP(ndx.[* FindAdd](`"one`"));&]
[s4; -|DUMP(ndx.FindAdd(`"two`"));&]
[s4; -|DUMP(ndx.FindAdd(`"three`"));&]
[s4; -|DUMP(ndx.FindAdd(`"two`"));&]
[s4; -|DUMP(ndx.FindAdd(`"three`"));&]
[s4; -|DUMP(ndx.FindAdd(`"one`"));&]
[s4; &]
[s6;  ndx.FindAdd(`"one`") `= 5&]
[s6;  ndx.FindAdd(`"two`") `= 6&]
[s6;  ndx.FindAdd(`"three`") `= 7&]
[s6;  ndx.FindAdd(`"two`") `= 6&]
[s6;  ndx.FindAdd(`"three`") `= 7&]
[s6;  ndx.FindAdd(`"one`") `= 5&]
[s3; Removing elements from random access sequence is always expensive, 
that is why rather than remove, Index supports [* Unlink] and [* UnlinkKey 
]operations, which leave element in Index but make it invisible 
for Find operation&]
[s4; -|ndx.[* Unlink](2);&]
[s4; -|ndx.[* UnlinkKey](`"kappa`");&]
[s4; &]
[s4; -|DUMP(ndx.Find(ndx`[2`]));&]
[s4; -|DUMP(ndx.Find(`"kappa`"));&]
[s4; &]
[s6;  ndx.Find(ndx`[2`]) `= `-1&]
[s6;  ndx.Find(`"kappa`") `= `-1&]
[s3; You can test whether element at given position is unlinked using 
[* IsUnlinked] method&]
[s4; -|DUMP(ndx.[* IsUnlinked](1));&]
[s4; -|DUMP(ndx.IsUnlinked(2));&]
[s4; &]
[s6;  ndx.IsUnlinked(1) `= 0&]
[s6;  ndx.IsUnlinked(2) `= 1&]
[s3; Unlinked positions can be reused by [* Put] method&]
[s4; -|ndx.[* Put](`"foo`");&]
[s5;  ndx `= `{ delta, beta, foo, delta, kappa, one, two, three `}&]
[s4; -|DUMP(ndx.Find(`"foo`"));&]
[s5;  ndx.Find(`"foo`") `= 2&]
[s3; You can also remove all unlinked elements from Index using [* Sweep] 
method&]
[s4; -|ndx.Sweep();&]
[s5;  ndx `= `{ delta, beta, foo, delta, one, two, three `}&]
[s3; As we said, operations directly removing or inserting elements 
of Index are very expensive, but sometimes this might not matter, 
so they are available too&]
[s4; -|ndx.[* Remove](1);&]
[s5;  ndx `= `{ delta, foo, delta, one, two, three `}&]
[s4; -|ndx.[* RemoveKey](`"two`");&]
[s5;  ndx `= `{ delta, foo, delta, one, three `}&]
[s4; -|ndx.[* Insert](0, `"insert`");&]
[s5;  ndx `= `{ insert, delta, foo, delta, one, three `}&]
[s3; Finally, [* PickKeys] operation allows you to obtain Vector of 
elements of Index in low constant time operation (while destroying 
source Index)&]
[s4; -|Vector<String> d `= ndx.[* PickKeys]();&]
[s4; -|Sort(d);&]
[s5;  d `= `{ delta, delta, foo, insert, one, three `}&]
[s3; &]
[s2; 9. Index and client types&]
[s3; In order to store elements to Index, they must be moveable (you 
can use [* ArrayIndex] for types that are not) and they must have 
defined the operator`=`= and a function to compute hash value. 
Notice usage THE of [* CombineHash] to combine hash values of types 
already known to U`+`+ into final result&]
[s4; &]
[s4; struct Person : Moveable<Person> `{&]
[s4; -|String name;&]
[s4; -|String surname;&]
[s4; &]
[s4; -|unsigned [* GetHashValue]() const          `{ return [* CombineHash](name, 
surname); `}&]
[s4; -|bool [* operator`=`=](const Person`& b) const `{ return name 
`=`= b.name `&`& surname `=`= b.surname; `}&]
[s4; &]
[s4; -|Person(String name, String surname) : name(name), surname(surname) 
`{`}&]
[s4; -|Person() `{`}&]
[s4; `};&]
[s4; &]
[s4; .......&]
[s4; &]
[s4; -|Index<Person> p;&]
[s4; -|p.Add(Person(`"John`", `"Smith`"));&]
[s4; -|p.Add(Person(`"Paul`", `"Carpenter`"));&]
[s4; -|p.Add(Person(`"Carl`", `"Engles`"));&]
[s4; -|      &]
[s4; -|DUMP(p.Find(Person(`"Paul`", `"Carpenter`")));&]
[s5;  p.Find(Person(`"Paul`", `"Carpenter`")) `= 1&]
[s3; &]
[s2; 10. VectorMap, ArrayMap&]
[s3; VectorMap is nothing more than a simple composition of Index 
and Vector. You can use [* Add] methods to put elements into the 
VectorMap&]
[s4; -|[* VectorMap]<String, Person> m;&]
[s4; -|&]
[s4; -|m.[* Add](`"1`", Person(`"John`", `"Smith`"));&]
[s4; -|m.Add(`"2`", Person(`"Carl`", `"Engles`"));&]
[s4; &]
[s4; -|Person`& p `= m.[* Add](`"3`");&]
[s4; -|p.name `= `"Paul`";&]
[s4; -|p.surname `= `"Carpenter`";&]
[s3; VectorMap provides constant access to its underlying Index and 
Vector&]
[s4; -|DUMP(m.[* GetKeys]());&]
[s4; -|DUMP(m.[* GetValues]());&]
[s4; &]
[s6; m.GetKeys() `= `{ 1, 2, 3 `}&]
[s6; m.GetValues() `= `{ John Smith, Carl Engles, Paul Carpenter 
`}&]
[s4; &]
[s3; You can use indices to iterate map contents&]
[s4; -|for(int i `= 0; i < m.GetCount(); i`+`+)&]
[s4; -|-|LOG(m.[* GetKey](i) << `": `" << m[* `[]i[* `]]);&]
[s4; &]
[s6; 1: John Smith&]
[s6; 2: Carl Engles&]
[s6; 3: Paul Carpenter&]
[s4; &]
[s3; You can use [* Find] method to retrieve position of element with 
required key&]
[s4; -|DUMP(m.[* Find](`"2`"));&]
[s5; m.Find(`"2`") `= 1&]
[s3; or [* Get] method to retrieve corresponding value&]
[s4; -|DUMP(m.[* Get](`"2`"));&]
[s5; m.Get(`"2`") `= Carl Engles&]
[s3; Passing key not present in VectorMap as Get parameter is a logic 
error, but there exists two parameter version that returns second 
parameter if key is not in VectorMap&]
[s4; -|DUMP(m.Get(`"33`", Person(`"unknown`", `"person`")));&]
[s5; m.Get(`"33`", Person(`"unknown`", `"person`")) `= unknown person&]
[s3; As with Index, you can use [* Unlink] to make elements invisible 
for Find operations&]
[s4; -|m.Unlink(1);&]
[s4; -|DUMP(m.Find(`"2`"));&]
[s5; m.Find(`"2`") `= `-1&]
[s3; You can use [* SetKey] method to change the key of the element&]
[s4; -|m.[* SetKey](1, `"33`");&]
[s4; -|DUMP(m.Get(`"33`", Person(`"unknown`", `"person`")));&]
[s5; m.Get(`"33`", Person(`"unknown`", `"person`")) `= Carl Engles&]
[s3; If there are more elements with the same key in VectorMap, you 
can iterate them using [* FindNext] method:&]
[s4; -|m.Add(`"33`", Person(`"Peter`", `"Pan`"));&]
[s4; &]
[s6; m.GetKeys() `= `{ 1, 33, 3, 33 `}&]
[s6; m.GetValues() `= `{ John Smith, Carl Engles, Paul Carpenter, 
Peter Pan `}&]
[s4; &]
[s4; -|int q `= m.Find(`"33`");&]
[s4; -|while(q >`= 0) `{&]
[s4; -|-|cout << m`[q`] << `'n`';&]
[s4; -|-|q `= m.[* FindNext](q);&]
[s4; -|`}&]
[s4; -|&]
[s6; Carl Engles&]
[s6; Peter Pan&]
[s4; &]
[s3; You can reuse unlinked positions using [* Put] method:&]
[s4; -|m.[* UnlinkKey](`"33`");&]
[s4; -|m.[* Put](`"22`", Person(`"Ali`", `"Baba`"));&]
[s4; -|m.Put(`"44`", Person(`"Ivan`", `"Wilks`"));&]
[s4; &]
[s6; m.GetKeys() `= `{ 1, 22, 3, 44 `}&]
[s6; m.GetValues() `= `{ John Smith, Ali Baba, Paul Carpenter, Ivan 
Wilks `}&]
[s4; &]
[s3; [* GetSortOrder] algorithm returns order of elements as Vector<int> 
container. You can use it to order content of VectorMap without 
actually moving its elements&]
[s4; -|bool operator<(const Person`& a, const Person`& b)&]
[s4; -|`{&]
[s4; -|-|return a.surname `=`= b.surname ? a.name < b.name&]
[s4; -|                              : a.surname < b.surname;&]
[s4; -|`}&]
[s4; &]
[s4; .......&]
[s4; &]
[s4; -|Vector<int> order `= [* GetSortOrder](m.GetValues());&]
[s5; order `= `{ 1, 2, 0, 3 `}&]
[s4; -|for(int i `= 0; i < order.GetCount(); i`+`+)&]
[s4; -|-|cout << m.GetKey(order`[i`]) << `": `" << m`[order`[i`]`] << 
`'n`';&]
[s4; &]
[s6; 22: Ali Baba&]
[s6; 3: Paul Carpenter&]
[s6; 1: John Smith&]
[s6; 44: Ivan Wilks&]
[s4; &]
[s3; You can get Vector of values or keys using [* PickValues] resp. 
[* PickKeys] methods in low constant time, while destroying content 
of source VectorMap&]
[s4; -|Vector<Person> ps `= m.[* PickValues]();&]
[s5; ps `= `{ John Smith, Ali Baba, Paul Carpenter, Ivan Wilks `}&]
[s3; If type of values does not satisfy requirements for Vector elements 
or if references to elements are needed, you can use [* ArrayMap] 
instead&]
[s4; -|[* ArrayMap]<String, Number> am;&]
[s4; -|am.Create<Integer>(`"A`").n `= 11;&]
[s4; -|am.Create<Double>(`"B`").n `= 2.1;&]
[s4; &]
[s6; am.GetKeys() `= `{ A, B `}&]
[s6; am.GetValues() `= `{ 11, 2.1 `}&]
[s4; &]
[s4; -|DUMP(am.Get(`"A`"));&]
[s4; -|DUMP(am.Find(`"B`"));&]
[s4; &]
[s6; am.Get(`"A`") `= 11&]
[s6; am.Find(`"B`") `= 1&]
[s3; &]
[s2; 11. One&]
[s3; One is a container that can store none or one element of T or 
derived from T. It functionally quite similiar to std`::unique`_ptr, 
but has some more convenient features (like Create method).&]
[s4; struct Base `{&]
[s4; -|virtual String Get() `= 0;&]
[s4; -|virtual `~Base() `{`}&]
[s4; `};&]
[s4; &]
[s4; struct Derived1 : Base `{&]
[s4; -|virtual String Get() `{ return `"Derived1`"; `}&]
[s4; `};&]
[s4; &]
[s4; struct Derived2 : Base `{&]
[s4; -|virtual String Get() `{ return `"Derived2`"; `}&]
[s4; `};&]
[s4; &]
[s4; void MakeDerived1(One<Base>`& t)&]
[s4; `{&]
[s4; -|t.Create<Derived1>();&]
[s4; `}&]
[s4; &]
[s4; void MakeDerived2(One<Base>`& t)&]
[s4; `{&]
[s4; -|t.Create<Derived2>();&]
[s4; `}&]
[s4; &]
[s4; .......&]
[s4; -|[* One]<Base> s;&]
[s3; Operator bool of one returns true if it contains an element:&]
[s4; -|DUMP([* (bool)]s);&]
[s4; &]
[s6; (bool)s `= false&]
[s4; &]
[s4; -|&]
[s4; -|s.[* Create]<Derived1>();&]
[s4; -|DUMP((bool)s);&]
[s4; -|DUMP(s`->Get());&]
[s4; &]
[s6; (bool)s `= true&]
[s6; s`->Get() `= Derived1&]
[s4; &]
[s3; Clear method removes the element from One:&]
[s4; -|s.[* Clear]();&]
[s4; -|DUMP((bool)s);&]
[s4; &]
[s6; (bool)s `= false&]
[s4; &]
[s4; &]
[s3; One represents a convenient and recommended method how to deal 
with class factories in U`+`+: Define them as a function (or method) 
with reference to One parameter, e.g.:&]
[s4; void MakeDerived1(One<Base>`& t)&]
[s4; `{&]
[s4; -|t.Create<Derived1>();&]
[s4; `}&]
[s4; &]
[s4; void MakeDerived2(One<Base>`& t)&]
[s4; `{&]
[s4; -|t.Create<Derived2>();&]
[s4; `}&]
[s4; &]
[s4; VectorMap<int, void (`*)(One<Base>`&)> factories;&]
[s4; &]
[s4; INITBLOCK `{&]
[s4; -|factories.Add(0, MakeDerived1);&]
[s4; -|factories.Add(1, MakeDerived2);&]
[s4; `};&]
[s4; &]
[s4; void Create(One<Base>`& t, int what)&]
[s4; `{&]
[s4; -|(`*factories.Get(what))(t);&]
[s4; `}&]
[s3; &]
[s2; 12. Any&]
[s3; Any is a container that can contain none or one element of [*/ any] 
type, the only requirement is that the type has default constructor. 
Important thing to remember is that [* Is] method matches [/ exact] 
type ignoring class hierarchies (FileIn is derived from Stream, 
but if Any contains FileIn, Is<Stream>() returns false).&]
[s4; void Do([* Any]`& x)&]
[s4; `{&]
[s4; -|if(x.[* Is]<String>())&]
[s4; -|-|LOG(`"String: `" << x.[* Get]<String>());&]
[s4; -|if(x.[* Is]<FileIn>()) `{&]
[s4; -|-|LOG(`"`-`-`- File: `");&]
[s4; -|-|LOG(LoadStream(x.[* Get]<FileIn>()));&]
[s4; -|-|LOG(`"`-`-`-`-`-`-`-`-`-`-`");&]
[s4; -|`}&]
[s4; -|if(x.[* IsEmpty]())&]
[s4; -|-|LOG(`"empty`");&]
[s4; `}&]
[s4; &]
[s4; .....&]
[s4; &]
[s4; -|Any x;&]
[s4; -|x.[* Create]<String>() `= `"Hello!`";&]
[s4; -|Do(x);&]
[s4; -|x.[* Create]<FileIn>().Open(GetDataFile(`"Ntl12.cpp`"));&]
[s4; -|Do(x);&]
[s4; -|x.[* Clear]();&]
[s4; -|Do(x);&]
[s3; &]
[s2; 13. InVector, InArray&]
[s3; InVector and InArray are vector types quite similar to Vector/Array, 
but they trade the speed of operator`[`] with the ability to 
insert or remove elements at any position quickly. You can expect 
operator`[`] to be about 10 times slower than in Vector (but 
that is still very fast), while Insert at any position scales 
well up to hundreds of megabytes of data (e.g. InVector containing 
100M of String elements is handled without problems).&]
[s4; -|[* InVector]<int> v;&]
[s4; -|for(int i `= 0; i < 1000000; i`+`+)&]
[s4; -|-|v.Add(i);&]
[s4; -|v.[* Insert](0, `-1); // This is fast&]
[s4; &]
[s3; While the interface of InVector/InArray is almost identical 
to Vector/Array, InVector/InArray in addition implements FindLowerBound/FindUpper
Bound functions `- while normal random access algorithms work, 
it is possible to provide InVector specific optimization that 
basically matches the performace of Find`*Bound on sample Vector.&]
[s4; &]
[s4; -|DUMP(v.[* FindLowerBound](55));&]
[s3; &]
[s2; 14. SortedIndex, SortedVectorMap, SortedArrayMap&]
[s3; SortedIndex is similar to regular Index, but keeps its elements 
in sorted order (sorting predicate is a template parameter, defaults 
to StdLess). Implementation is using InVector, so it works fine 
even with very large number of elements (performance is similar 
to tree based std`::set). Unlike Index, SortedIndex provides lower/upper 
bounds searches, so it allow range search.&]
[s4; -|[* SortedIndex]<int> x;&]
[s4; -|x.Add(5);&]
[s4; -|x.Add(3);&]
[s4; -|x.Add(7);&]
[s4; -|x.Add(1);&]
[s4; -|&]
[s4; -|DUMPC(x);&]
[s4; -|DUMP(x.[* Find](3));&]
[s4; -|DUMP(x.[* Find](3));&]
[s4; -|DUMP(x.[* FindLowerBound](3));&]
[s4; -|DUMP(x.[* FindUpperBound](6));&]
[s4; &]
[s3; SortedVectorMap and SortedArrayMap are then SortedIndex based 
equivalents to VectorMap/ArrayMap `- maps that keep keys sorted:&]
[s4; -|[* SortedVectorMap]<String, int> m;&]
[s4; -|m.Add(`"zulu`", 11);&]
[s4; -|m.Add(`"frank`", 12);&]
[s4; -|m.Add(`"alfa`", 13);&]
[s4; -|&]
[s4; -|DUMPM(m);&]
[s4; -|DUMP(m.[* Get](`"zulu`"));&]
[s3; &]
[s2; 15. Tuples&]
[s3; U`+`+ has template classes Tuple2, Tuple3 and Tuple4 for combining 
2`-4 values with different types. These are quite similiar to 
std`::tuple class, with some advantages.&]
[s3; To create a Tuple value, you can use the Tuple function. If 
correct types canot be deduced from parameters, you can specify 
them explicitly:&]
[s4; -|Tuple3<int, String, String> x `= [* Tuple]<int, String, String>(12, 
`"hello`", `"world`");&]
[s4; &]
[s3; Individual values are accessible as members a .. d:&]
[s4; &]
[s4; -|DUMP(x.a);&]
[s4; -|DUMP(x.b);&]
[s4; -|DUMP(x.c);&]
[s4; -|&]
[s3; As long as all individual types have conversion to String (AsString), 
the tuple also has such conversion and thus can e.g. be easily 
logged:&]
[s4; &]
[s4; -|DUMP(x);&]
[s4; &]
[s3; Also, as long as individual types have defined GetHashValue, 
so does Tuple:&]
[s4; &]
[s4; -|DUMP(GetHashValue(x));&]
[s4; &]
[s3; As long as individual types have defined operator`=`=, Tuple 
has defined operator`=`= and operator!`=&]
[s4; &]
[s4; -|Tuple3<int, String, String> y `= x;&]
[s4; -|DUMP(x !`= y);&]
[s4; &]
[s3; Finally, as long as all individual types have defined SgnCompare 
(most U`+`+ types have), Tuple has SgnCompare, Compare method 
and operators <, <`=, >, >`=:&]
[s4; &]
[s4; -|DUMP(x.Compare(y));&]
[s4; -|&]
[s4; -|y.b `= `"a`";&]
[s4; -|&]
[s4; -|DUMP(SgnCompare(x, y));&]
[s4; -|DUMP(x < y);&]
[s4; -|&]
[s4; &]
[s3; U`+`+ Tuples are strictly designed as POD type, which allows 
POD arrays to be intialized with classic C style:&]
[s4; -|static Tuple2<int, const char `*> map`[`] `= `{&]
[s4; -|-|`{ 1, `"one`" `},&]
[s4; -|-|`{ 2, `"one`" `},&]
[s4; -|-|`{ 3, `"one`" `},&]
[s4; -|`};&]
[s4; -|&]
[s3; &]
[s3; Simple FindTuple template function is provided to search for 
tuple based on the first value:&]
[s3; &]
[s2; 15. Sorting&]
[s3; IndexSort is sort variant that is able to sort two random access 
container (like Vector or Array) of the same size, based on values 
in on of containers:&]
[s4; -|Vector<int> a;&]
[s4; -|Vector<String> b;-|&]
[s4; -|&]
[s4; -|a << 5 << 10 << 2 << 9 << 7 << 3;&]
[s4; -|b << `"five`" << `"ten`" << `"two`" << `"nine`" << `"seven`" 
<< `"three`";&]
[s4; -|&]
[s4; -|[* IndexSort](a, b);&]
[s4; &]
[s6; a `= `[2, 3, 5, 7, 9, 10`]&]
[s6; b `= `[two, three, five, seven, nine, ten`]&]
[s4; &]
[s4; -|[* IndexSort](b, a);&]
[s4; &]
[s6; a `= `[5, 9, 7, 10, 3, 2`]&]
[s6; b `= `[five, nine, seven, ten, three, two`]&]
[s3; Order of sorted items is defined by sorting predicate. By default, 
operator< comparing items of container is used (this predicate 
can be provided by StdLess template), but it is possible to specify 
different sorting order, e.g. by using predefined StdGreater 
predicate:&]
[s4; -|Sort(a, [* StdGreater]<int>());&]
[s4; &]
[s6; a `= `[10, 9, 7, 5, 3, 2`]&]
[s3; Sometimes, instead of sorting items in the container, it is 
useful to know the order of items as sorted, using GetSortOrder:&]
[s4; -|Vector<int> o `= [* GetSortOrder](a);&]
[s4; &]
[s6; o `= `[5, 4, 3, 2, 1, 0`]&]
[s3; FieldRelation predefined predicate can be used to sort container 
of structures by specific field:&]
[s4; -|Vector<Point> p;&]
[s4; -|p << Point(5, 10) << Point(7, 2) << Point(4, 8) << Point(1, 
0);&]
[s4; -|&]
[s4; -|Sort(p, [* FieldRelation](`&Point`::x, StdLess<int>()));&]
[s4; &]
[s6; p `= `[`[1, 0`], `[4, 8`], `[5, 10`], `[7, 2`]`]&]
[s3; MethodRelation is good for sorting of structures based on constant 
method of structure:-|&]
[s4; struct Foo `{&]
[s4; -|String a;&]
[s4; -|&]
[s4; -|int [* Get]() const `{ return atoi(a); `}&]
[s4; -|....&]
[s4; `};&]
[s4; ....&]
[s4; -|Array<Foo> f;&]
[s4; -|f << `"12`" << `"1`" << `"10`" << `"7`" << `"5`";&]
[s4; -|&]
[s4; -|Sort(f, [* MethodRelation](`&Foo`::[* Get], StdLess<int>()));&]
[s4; &]
[s6; f `= `[1, 5, 7, 10, 12`]&]
[s3; Normal Sort is not stable `- equal items can appear in sorted 
sequence in random order. If maintaining original order of equal 
items is important, use StableSort variant (with slight performance 
penalty):&]
[s4; -|Vector<Point> t;&]
[s4; -|t << Point(10, 10) << Point(7, 1) << Point(7, 2) << Point(7, 
3) << Point(1, 0);&]
[s4; -|[* StableSort](t, FieldRelation(`&Point`::x, StdLess<int>()));&]
[s4; &]
[s6; t `= `[`[1, 0`], `[7, 1`], `[7, 2`], `[7, 3`], `[10, 10`]`]&]
[s3; &]
[s2; Recommended tutorials:&]
[s3; If you want to learn more, we have several tutorials that you 
can find useful:&]
[s3;l160;i150;O0; [^topic`:`/`/Core`/srcdoc`/CoreTutorial`$en`-us^ U`+`+ 
Core value types] `- if you miss this one`- it it a good occasion 
to catch up. Here you will learn about Core basics.&]
[s0; [^topic`:`/`/Sql`/srcdoc`/tutorial`$en`-us^ SQL] `- learn how 
to use databases with U`+`+ framework.&]
[s0; ]]