diff --git a/uppsrc/Core/srcdoc.tpp/Tutorial_en-us.tpp b/uppsrc/Core/srcdoc.tpp/Tutorial_en-us.tpp index 94a529b3c..f38a76218 100644 --- a/uppsrc/Core/srcdoc.tpp/Tutorial_en-us.tpp +++ b/uppsrc/Core/srcdoc.tpp/Tutorial_en-us.tpp @@ -26,6 +26,7 @@ topic "U++ Core Tutorial"; [s2;%% U`+`+ Core Tutorial&] [s22; Table of contents&] [s0;3 &] +[s0;3 &] [s0; [^`#Chapter`_1^ 1. Basics]&] [s0; ___[^`#Section`_1`_1^ 1.1 Logging]&] [s0; ___[^`#Section`_1`_2^ 1.2 String]&] @@ -80,7 +81,7 @@ topic "U++ Core Tutorial"; [s0; ___[^`#Section`_7`_4^ 7.4 CoWork]&] [s0; ___[^`#Section`_7`_5^ 7.5 AsyncWork]&] [s0; ___[^`#Section`_7`_6^ 7.6 CoPartition]&] -[s0; ___[^`#Section`_7`_7^ 7.7 CoWork loop method]&] +[s0; ___[^`#Section`_7`_7^ 7.7 CoDo]&] [s0; ___[^`#Section`_7`_8^ 7.8 Parallel algorithms]&] [s22;:Chapter`_1: 1. Basics&] [s3;:Section`_1`_1: 1.1 Logging&] @@ -124,9 +125,9 @@ variable name and value:&] [s7; DUMPHEX(h);&] [s0; &] [s17; x `= 0x7b&] -[s17; h `= Memory at 0x00000084D9F1FC30, size 0x3 `= 3&] -[s17; `+0 0x00000084D9F1FC30 66 6F 6F - foo &] +[s17; h `= Memory at 0x025BFCF8, size 0x3 `= 3&] +[s17; `+0 0x025BFCF8 66 6F 6F + foo &] [s0; &] [s5; To log the value of a container (or generic Range), you can either use normal [*C@5 LOG] / [*C@5 DUMP]:&] @@ -369,9 +370,9 @@ data, including zeroes:&] [s7; &] [s7; DUMPHEX(a);&] [s0; &] -[s17; a `= Memory at 0x00000084D9F1FB90, size 0x5 `= 5&] -[s17; `+0 0x00000084D9F1FB90 31 32 33 34 00 - 1234. &] +[s17; a `= Memory at 0x025BFD58, size 0x5 `= 5&] +[s17; `+0 0x025BFD58 31 32 33 34 00 + 1234. &] [s0; &] [s3;H4;:Section`_1`_3: 1.3 StringBuffer&] [s5; If you need a direct write access to [*C@5 String]`'s C`-string @@ -473,7 +474,7 @@ concrete types.&] [s7; &] [s7; DUMP(date);&] [s0; &] -[s17; date `= 07/08/2018&] +[s17; date `= 09/05/2019&] [s0; &] [s5; All data members of [*C@5 Date] structure are public:&] [s0; &] @@ -483,9 +484,9 @@ date members&] would log&] [s7; DUMP((int)date.day); // as characters&] [s0; &] -[s17; (int)date.year `= 2018&] -[s17; (int)date.month `= 7&] -[s17; (int)date.day `= 8&] +[s17; (int)date.year `= 2019&] +[s17; (int)date.month `= 9&] +[s17; (int)date.day `= 5&] [s0; &] [s5; Dates can be compared:&] [s0; &] @@ -500,15 +501,15 @@ ing goes to the next/previous day:&] [s7; DUMP(`-`-date);&] [s7; DUMP(`+`+date);&] [s0; &] -[s17; date `+ 1 `= 07/09/2018&] -[s17; `-`-date `= 07/07/2018&] -[s17; `+`+date `= 07/08/2018&] +[s17; date `+ 1 `= 09/06/2019&] +[s17; `-`-date `= 09/04/2019&] +[s17; `+`+date `= 09/05/2019&] [s0; &] [s5; Subtraction of dates yields a number of days between them:&] [s0; &] [s7; DUMP(date `- Date(2000, 1, 1));&] [s0; &] -[s17; date `- Date(2000, 1, 1) `= 6763&] +[s17; date `- Date(2000, 1, 1) `= 7187&] [s0; &] [s5; There are several [*C@5 Date] and calendar related functions:&] [s0; &] @@ -534,7 +535,7 @@ ing goes to the next/previous day:&] [s0; &] [s7; DUMP(DayOfWeek(date)); // 0 is Sunday&] [s0; &] -[s17; DayOfWeek(date) `= 0&] +[s17; DayOfWeek(date) `= 4&] [s0; &] [s0; &] [s7; DUMP(LastDayOfMonth(date));&] @@ -544,11 +545,11 @@ ing goes to the next/previous day:&] [s7; DUMP(DayOfYear(date)); // number of days since Jan`-1 `+ 1&] [s7; DUMP(DayOfYear(Date(2016, 1, 1)));&] [s0; &] -[s17; LastDayOfMonth(date) `= 07/31/2018&] -[s17; FirstDayOfMonth(date) `= 07/01/2018&] -[s17; LastDayOfYear(date) `= 12/31/2018&] -[s17; FirstDayOfYear(date) `= 01/01/2018&] -[s17; DayOfYear(date) `= 189&] +[s17; LastDayOfMonth(date) `= 09/30/2019&] +[s17; FirstDayOfMonth(date) `= 09/01/2019&] +[s17; LastDayOfYear(date) `= 12/31/2019&] +[s17; FirstDayOfYear(date) `= 01/01/2019&] +[s17; DayOfYear(date) `= 248&] [s17; DayOfYear(Date(2016, 1, 1)) `= 1&] [s0; &] [s0; &] @@ -559,10 +560,10 @@ between two dates&] partial months`' between two dates&] [s7; DUMP(AddYears(date, 2));&] [s0; &] -[s17; AddMonths(date, 20) `= 03/08/2020&] +[s17; AddMonths(date, 20) `= 05/05/2021&] [s17; GetMonths(date, date `+ 100) `= 3&] [s17; GetMonthsP(date, date `+ 100) `= 4&] -[s17; AddYears(date, 2) `= 07/08/2020&] +[s17; AddYears(date, 2) `= 09/05/2021&] [s0; &] [s0; &] [s7; DUMP(GetWeekDate(2015, 1));&] @@ -602,11 +603,11 @@ time:&] [s7; DUMP((int)time.minute);&] [s7; DUMP((int)time.second);&] [s0; &] -[s17; time `= 07/08/2018 09:28:56&] -[s17; (Date)time `= 07/08/2018&] -[s17; (int)time.hour `= 9&] -[s17; (int)time.minute `= 28&] -[s17; (int)time.second `= 56&] +[s17; time `= 09/05/2019 14:48:55&] +[s17; (Date)time `= 09/05/2019&] +[s17; (int)time.hour `= 14&] +[s17; (int)time.minute `= 48&] +[s17; (int)time.second `= 55&] [s0; &] [s5; Times can be compared:&] [s0; &] @@ -633,10 +634,10 @@ but numbers represent seconds (using [*C@5 int64] datatype):&] is in days&] [s7; DUMP(time `- ToTime(date)); // Time `- Time is in seconds&] [s0; &] -[s17; time `+ 1 `= 07/08/2018 09:28:57&] -[s17; time `+ 24 `* 3600 `= 07/09/2018 09:28:56&] +[s17; time `+ 1 `= 09/05/2019 14:48:56&] +[s17; time `+ 24 `* 3600 `= 09/06/2019 14:48:55&] [s17; time `- date `= 0&] -[s17; time `- ToTime(date) `= 34136&] +[s17; time `- ToTime(date) `= 53335&] [s0; &] [s5; [*C@5 Time] defines era limits too:&] [s0; &] @@ -691,9 +692,9 @@ items predefined by U`+`+:&] [s7; DUMP(LoadFile(ConfigFile(`"test.txt`")));&] [s7; DUMP(sout);&] [s0; &] -[s17; LoadFile(ConfigFile(`"test.txt`")) `= 1.23 07/08/2018 07/08/2018 -09:28:56&] -[s17; sout `= 1.23 07/08/2018 07/08/2018 09:28:56&] +[s17; LoadFile(ConfigFile(`"test.txt`")) `= 1.23 09/05/2019 09/05/2019 +14:48:55&] +[s17; sout `= 1.23 09/05/2019 09/05/2019 14:48:55&] [s0; &] [s5; Getting client types involved into this schema is not too difficult, all you need to do is to add [*C@5 ToString] method:&] @@ -752,14 +753,14 @@ too:&] [s7; &] [s7; DUMP(GetHashValue(x));&] [s0; &] -[s17; GetHashValue(x) `= 4272824901&] +[s17; GetHashValue(x) `= 749369797&] [s0; &] [s0; &] [s7; x.a << `'!`';&] [s7; &] [s7; DUMP(GetHashValue(x));&] [s0; &] -[s17; GetHashValue(x) `= 3378606405&] +[s17; GetHashValue(x) `= 1076203717&] [s0; &] [s3;H4;:Section`_1`_8: 1.8 SgnCompare and CombineCompare&] [s5; Traditional approach of C language of representing comparison @@ -1068,10 +1069,9 @@ in both little`-endian and big`-endian modes:&] [s7; ss.Put32be(0x12345678);&] [s7; DUMPHEX(ss.GetResult());&] [s0; &] -[s17; ss.GetResult() `= Memory at 0x00000084D9F1F990, size 0x8 `= -8&] -[s17; `+0 0x00000084D9F1F990 78 56 34 12 12 34 56 78 - xV4..4Vx &] +[s17; ss.GetResult() `= Memory at 0x025BF828, size 0x8 `= 8&] +[s17; `+0 0x025BF828 78 56 34 12 12 34 56 78 + xV4..4Vx &] [s0; &] [s0; &] [s7; StringStream ss2(ss.GetResult());&] @@ -1119,12 +1119,12 @@ them via [*C@5 Out] virtual method:&] [s7; os << `"This is a test `" << 12345;&] [s7; os.Close();&] [s0; &] -[s17; String((const char `*)data, size) `= Memory at 0x000001E4641A1AE0, -size 0x14 `= 20&] -[s17; `+0 0x000001E4641A1AE0 54 68 69 73 20 69 73 20 61 20 74 -65 73 74 20 31 This is a test 1&] -[s17; `+16 0x000001E4641A1AF0 32 33 34 35 - 2345 &] +[s17; String((const char `*)data, size) `= Memory at 0x0750F7D0, size +0x14 `= 20&] +[s17; `+0 0x0750F7D0 54 68 69 73 20 69 73 20 61 20 74 65 73 74 +20 31 This is a test 1&] +[s17; `+16 0x0750F7E0 32 33 34 35 + 2345 &] [s0; &] [s5; [*C@5 TeeStream] sends output data to two separate streams:&] [s0; &] @@ -1147,12 +1147,12 @@ block to stream data:&] [s7; while(!ms.IsEof())&] [s7; -|DUMPHEX(ms.GetLine());&] [s0; &] -[s17; ms.GetLine() `= Memory at 0x00000084D9F1F5F8, size 0x9 `= 9&] -[s17; `+0 0x00000084D9F1F5F8 53 6F 6D 65 20 6C 69 6E 65 - Some line &] -[s17; ms.GetLine() `= Memory at 0x00000084D9F1F5F8, size 0xC `= 12&] -[s17; `+0 0x00000084D9F1F5F8 41 6E 6F 74 68 65 72 20 6C 69 6E -65 Another line &] +[s17; ms.GetLine() `= Memory at 0x025BF6AC, size 0x9 `= 9&] +[s17; `+0 0x025BF6AC 53 6F 6D 65 20 6C 69 6E 65 + Some line &] +[s17; ms.GetLine() `= Memory at 0x025BF6AC, size 0xC `= 12&] +[s17; `+0 0x025BF6AC 41 6E 6F 74 68 65 72 20 6C 69 6E 65 + Another line &] [s0; &] [s3;H4;:Section`_2`_3: 2.3 Binary serialization&] [s5; Serialization is a mechanism that converts structured data to/from @@ -1264,7 +1264,7 @@ original [*C@5 MyFoo], we can branch on previously stored [*C@5 version]:&] [s7; DUMP(foo3.number);&] [s7; DUMP(foo3.color);&] [s0; &] -[s17; foo3.number `= 1679266384&] +[s17; foo3.number `= 0&] [s17; foo3.color `= Color(Null)&] [s0; &] [s5; Note: [*C@5 operator/] is Stream method with several overloads @@ -1396,7 +1396,7 @@ to this value.&] [s7; &] [s7; DUMP(v);&] [s0; &] -[s17; v `= `[1026, 994, 1000, 1042, 989, 947, 1008, 957, 1004, 1033`]&] +[s17; v `= `[986, 977, 1018, 957, 1004, 1023, 986, 992, 996, 1061`]&] [s0; &] [s5; Referencing invalid index is undefined operation. Sometimes however it is useful to return the element value if index is @@ -1407,7 +1407,7 @@ with two parameter Get method:&] [s7; DUMP(v.Get(`-10, 0));&] [s7; DUMP(v.Get(13, `-1));&] [s0; &] -[s17; v.Get(4, 0) `= 989&] +[s17; v.Get(4, 0) `= 1004&] [s17; v.Get(`-10, 0) `= 0&] [s17; v.Get(13, `-1) `= `-1&] [s0; &] @@ -1417,7 +1417,7 @@ with two parameter Get method:&] [s7; &] [s7; DUMP(v);&] [s0; &] -[s17; v `= `[947, 957, 989, 994, 1000, 1004, 1008, 1026, 1033, 1042`]&] +[s17; v `= `[957, 977, 986, 986, 992, 996, 1004, 1018, 1023, 1061`]&] [s0; &] [s3;H4;:Section`_3`_3: 3.3 Transfer issues&] [s5; Often you need to pass content of one container to another of @@ -1523,15 +1523,15 @@ to it:&] [s7; DUMPC(dist);&] [s0; &] [s17; dist:&] -[s17; -|`[0`] `= Test 5: `[2079, 1931, 2027, 1987, 1976`]&] -[s17; -|`[1`] `= Test 6: `[1710, 1676, 1687, 1653, 1609, 1665`]&] -[s17; -|`[2`] `= Test 7: `[1465, 1366, 1421, 1430, 1459, 1441, 1418`]&] -[s17; -|`[3`] `= Test 8: `[1233, 1288, 1268, 1238, 1271, 1290, 1205, -1207`]&] -[s17; -|`[4`] `= Test 9: `[1059, 1117, 1104, 1110, 1100, 1165, 1100, -1091, 1154`]&] -[s17; -|`[5`] `= Test 10: `[1003, 963, 940, 1018, 1041, 1020, 987, 1033, -1012, 983`]&] +[s17; -|`[0`] `= Test 5: `[1986, 2026, 1997, 2016, 1975`]&] +[s17; -|`[1`] `= Test 6: `[1632, 1655, 1692, 1633, 1677, 1711`]&] +[s17; -|`[2`] `= Test 7: `[1441, 1397, 1423, 1502, 1423, 1393, 1421`]&] +[s17; -|`[3`] `= Test 8: `[1245, 1276, 1280, 1252, 1247, 1222, 1197, +1281`]&] +[s17; -|`[4`] `= Test 9: `[1132, 1146, 1139, 1135, 1070, 1138, 1092, +1050, 1098`]&] +[s17; -|`[5`] `= Test 10: `[999, 1083, 934, 909, 983, 1013, 1031, 1048, +975, 1025`]&] [s0; &] [s5; Another possibility is to use [*C@5 Vector`::Add(T`&`&)] method, which uses pick`-constructor instead of deep`-copy constructor. @@ -1776,8 +1776,8 @@ but make it invisible for [*C@5 Find] operation:&] [s7; DUMP(ndx);&] [s7; DUMP(ndx.Find(`"foo`"));&] [s0; &] -[s17; ndx `= `[alfa, alfa, foo, delta, kappa, one, two, three`]&] -[s17; ndx.Find(`"foo`") `= 2&] +[s17; ndx `= `[alfa, alfa, gamma, delta, foo, one, two, three`]&] +[s17; ndx.Find(`"foo`") `= 4&] [s0; &] [s5; You can also remove all unlinked elements from [*C@5 Index] using [*C@5 Sweep] method:&] @@ -1786,7 +1786,7 @@ but make it invisible for [*C@5 Find] operation:&] [s7; &] [s7; DUMP(ndx);&] [s0; &] -[s17; ndx `= `[alfa, alfa, foo, delta, one, two, three`]&] +[s17; ndx `= `[alfa, alfa, delta, foo, one, two, three`]&] [s0; &] [s5; Operations directly removing or inserting elements of Index are expensive, but available too:&] @@ -1795,21 +1795,21 @@ are expensive, but available too:&] [s7; &] [s7; DUMP(ndx);&] [s0; &] -[s17; ndx `= `[alfa, foo, delta, one, two, three`]&] +[s17; ndx `= `[alfa, delta, foo, one, two, three`]&] [s0; &] [s0; &] [s7; ndx.RemoveKey(`"two`");&] [s7; &] [s7; DUMP(ndx);&] [s0; &] -[s17; ndx `= `[alfa, foo, delta, one, three`]&] +[s17; ndx `= `[alfa, delta, foo, one, three`]&] [s0; &] [s0; &] [s7; ndx.Insert(0, `"insert`");&] [s7; &] [s7; DUMP(ndx);&] [s0; &] -[s17; ndx `= `[insert, alfa, foo, delta, one, three`]&] +[s17; ndx `= `[insert, alfa, delta, foo, one, three`]&] [s0; &] [s5; PickKeys operation allows you to obtain Vector of elements of Index in low constant time operation (while destroying source @@ -1819,7 +1819,7 @@ Index)&] [s7; &] [s7; DUMP(d);&] [s0; &] -[s17; d `= `[insert, alfa, foo, delta, one, three`]&] +[s17; d `= `[insert, alfa, delta, foo, one, three`]&] [s0; &] [s5; Pick`-assigning [*C@5 Vector] to [*C@5 Index] is supported as well:&] [s0; &] @@ -1829,7 +1829,7 @@ Index)&] [s7; &] [s7; DUMP(ndx);&] [s0; &] -[s17; ndx `= `[test, alfa, foo, delta, one, three`]&] +[s17; ndx `= `[test, alfa, delta, foo, one, three`]&] [s0; &] [s3;H4;:Section`_3`_9: 3.9 Index and client types&] [s5; In order to store elements to [*C@5 Index], they type must be @@ -2026,8 +2026,8 @@ you can iterate them using [*C@5 FindNext] method:&] [s7; &] [s7; DUMP(m);&] [s0; &] -[s17; m `= `{1: John Smith, 22: Ali Baba, 3: Peter Carpenter, 44: Ivan -Wilks`}&] +[s17; m `= `{1: John Smith, 44: Ivan Wilks, 3: Peter Carpenter, 22: Ali +Baba`}&] [s0; &] [s5; [*C@5 PickValues] / [*C@5 PickIndex] / [*C@5 PickKeys] / pick internal [*C@5 Vector] / [*C@5 Index] / [*C@5 Vector] of [*C@5 Index]:&] @@ -2039,8 +2039,8 @@ Wilks`}&] [s7; DUMP(ks);&] [s7; DUMP(m);&] [s0; &] -[s17; ps `= `[John Smith, Ali Baba, Peter Carpenter, Ivan Wilks`]&] -[s17; ks `= `[1, 22, 3, 44`]&] +[s17; ps `= `[John Smith, Ivan Wilks, Peter Carpenter, Ali Baba`]&] +[s17; ks `= `[1, 44, 3, 22`]&] [s17; m `= `{`}&] [s0; &] [s5; [*C@5 VectorMap] pick constructor to create map by picking:&] @@ -2051,8 +2051,8 @@ Wilks`}&] [s7; &] [s7; DUMP(m);&] [s0; &] -[s17; m `= `{Changed key: John Smith, 22: Ali Baba, 3: Peter Carpenter, -44: Ivan Wilks`}&] +[s17; m `= `{Changed key: John Smith, 44: Ivan Wilks, 3: Peter Carpenter, +22: Ali Baba`}&] [s0; &] [s5; [*C@5 ArrayMap] is composition of Index and Array, for cases where Array is better fit for value type (e.g. they are polymorphic):&] @@ -2280,7 +2280,7 @@ so does [*C@5 Tuple]:&] [s0; &] [s7; DUMP(GetHashValue(x));&] [s0; &] -[s17; GetHashValue(x) `= 834842890&] +[s17; GetHashValue(x) `= 2387239184&] [s0; &] [s5; As long as individual types have defined [*C@5 operator`=`=], [*C@5 Tuple] has defined [*C@5 operator`=`=] and [*C@5 operator!`=]:&] @@ -2434,11 +2434,11 @@ easier:&] [s0; &] [s17; typeid(ValueTypeOf).name() `= int&] [s17; typeid(ValueTypeOf).name() `= int&] -[s17; typeid(IteratorOf).name() `= int `* `_`_ptr64&] +[s17; typeid(IteratorOf).name() `= int `*&] [s17; typeid(ConstIteratorOf).name() -`= int `* `_`_ptr64&] +`= int `*&] [s17; typeid(SubRangeOf>).name() `= class Upp`::SubRangeClass&] +`*>&] [s0; &] [s5; While containers themselves and SubRange are the two most common range types, U`+`+ has two special ranges. [*C@5 ConstRange] simply @@ -2690,11 +2690,11 @@ is for the most part seamless:&] [s0; &] [s17; a `= 1&] [s17; b `= 2.34&] -[s17; c `= 07/08/2018&] +[s17; c `= 09/05/2019&] [s17; d `= hello&] [s17; x `= 1&] [s17; y `= 2.34&] -[s17; z `= 07/08/2018&] +[s17; z `= 09/05/2019&] [s17; s `= hello&] [s0; &] [s5; As for primitive types, Value seamlessly works with [*C@5 int], @@ -2726,7 +2726,7 @@ as it is supported by these types):&] [s0; &] [s17; i `= 1&] [s17; j `= 2&] -[s17; k `= 07/08/2018 00:00:00&] +[s17; k `= 09/05/2019 00:00:00&] [s17; t `= hello&] [s0; &] [s5; To determine type of value stored in [*C@5 Value], you can use @@ -3353,16 +3353,16 @@ thread to [*C@5 Wait] for its completion:&] [s0; &] [s17; In the main thread 0&] [s17; In the thread 0&] -[s17; In the main thread 1&] [s17; In the thread 1&] -[s17; In the main thread 2&] +[s17; In the main thread 1&] [s17; In the thread 2&] -[s17; In the main thread 3&] +[s17; In the main thread 2&] [s17; In the thread 3&] -[s17; In the main thread 4&] +[s17; In the main thread 3&] [s17; In the thread 4&] -[s17; About to wait for thread to finish&] +[s17; In the main thread 4&] [s17; In the thread 5&] +[s17; About to wait for thread to finish&] [s17; In the thread 6&] [s17; In the thread 7&] [s17; In the thread 8&] @@ -3410,7 +3410,7 @@ code demonstrates why:&] [s7; t.Wait();&] [s7; DUMP(sum);&] [s0; &] -[s17; sum `= 1031062&] +[s17; sum `= 1041445&] [s0; &] [s5; While the expected value is 2000000, produced value is different. The problem is that both thread read / modify / write [*C@5 sum] @@ -3536,12 +3536,12 @@ testing data&] [s0; &] [s17; w `= `[Lorem, ipsum, dolor, sit, amet, consectetur, adipiscing, elit, aliqua, Ut, enim, ad, minim, veniam, quis, nostrud, exercitation, -sed, do, eiusmod, tempor, incididunt, ut, labore, et, dolore, -magna, ullamco, laboris, nisi, aliquip, ex, ea, commodo, consequat, -esse, cillum, eu, fugiat, nulla, pariatur, Excepteur, officia, +esse, cillum, dolore, eu, fugiat, nulla, pariatur, Excepteur, +ullamco, laboris, nisi, ut, aliquip, ex, ea, commodo, consequat, +Duis, aute, irure, in, reprehenderit, voluptate, velit, officia, deserunt, mollit, anim, id, est, laborum, sint, occaecat, cupidatat, -non, proident, sunt, in, culpa, qui, Duis, aute, irure, reprehenderit, -voluptate, velit`]&] +non, proident, sunt, culpa, qui, sed, do, eiusmod, tempor, incididunt, +labore, et, magna`]&] [s0; &] [s5; Adding words to [*C@5 w] requires [*C@5 Mutex]. Alternative to this `'result gathering`' [*C@5 Mutex] is [*C@5 CoWork`::FinLock]. The @@ -3570,12 +3570,12 @@ end of CoWork job&] [s0; &] [s17; w `= `[Lorem, ipsum, dolor, sit, amet, consectetur, adipiscing, elit, aliqua, Ut, enim, ad, minim, veniam, quis, nostrud, exercitation, -sed, do, eiusmod, tempor, incididunt, ut, labore, et, dolore, -magna, ullamco, laboris, nisi, aliquip, ex, ea, commodo, consequat, -esse, cillum, eu, fugiat, nulla, pariatur, Excepteur, officia, +esse, cillum, dolore, eu, fugiat, nulla, pariatur, Excepteur, +ullamco, laboris, nisi, ut, aliquip, ex, ea, commodo, consequat, +Duis, aute, irure, in, reprehenderit, voluptate, velit, officia, deserunt, mollit, anim, id, est, laborum, sint, occaecat, cupidatat, -non, proident, sunt, in, culpa, qui, Duis, aute, irure, reprehenderit, -voluptate, velit`]&] +non, proident, sunt, culpa, qui, sed, do, eiusmod, tempor, incididunt, +labore, et, magna`]&] [s0; &] [s5; Of course, the code performed after [*C@5 FinLock] should not take long, otherwise there is negative impact on all [*C@5 CoWork] @@ -3639,6 +3639,14 @@ be checked in job routine using [*C@5 CoWork`::IsCanceled]:&] [s17; Job was canceled&] [s17; Job was canceled&] [s17; Job was canceled&] +[s17; Job was canceled&] +[s17; Job was canceled&] +[s17; Job was canceled&] +[s17; Job was canceled&] +[s17; Job was canceled&] +[s17; Job was canceled&] +[s17; Job was canceled&] +[s17; Job was canceled&] [s0; &] [s5; Canceling CoWork is common in GUI applications.&] [s3;H4;:Section`_7`_5: 7.5 [C@5 AsyncWork]&] @@ -3766,16 +3774,14 @@ h) `{&] [s0; &] [s17; sum `= 49995000&] [s0; &] -[s3;H4;:Section`_7`_7: 7.7 CoWork loop method&] -[s5; An alternative to [*C@5 CoPartition] is `'loop`' method of [*C@5 CoWork] -([*C@5 Loop] method with synonym [*C@5 operator`*]). In this pattern, +[s3;H4;:Section`_7`_7: 7.7 CoDo&] +[s5; An alternative to [*C@5 CoPartition] is [*C@5 CoDo]. In this pattern, the job is simply started in all threads and the code is responsible -for scheduling the work. [*C@5 Loop] / [*C@5 operator`*] waits for -all started threads to finish. For scheduling, it is possible -to use internal [*C@5 CoWork] index counter, which is set to 0 -at the start of [*C@5 Loop] / [*C@5 operator`*]. This way, the overhead -associated with creating lambdas and scheduling them is kept -to the minimum.&] +for scheduling the work. [*C@5 CoDo] waits for all started threads +to finish. Scheduling is the responsibility of client code, but +can be easily managed using the std`::atomic counter. This way, +the overhead associated with creating lambdas and scheduling +them is kept to the minimum (basically the cost of atomic increment).&] [s0; &] [s7; Vector data;&] [s7; for(int i `= 0; i < 100; i`+`+)&] @@ -3783,15 +3789,15 @@ to the minimum.&] [s7; &] [s7; double sum `= 0;&] [s7; &] -[s7; CoWork co;&] -[s7; co `* `[`&`] `{&] -[s7; -|int i;&] +[s7; std`::atomic ii `= 0;&] +[s7; &] +[s7; CoDo(`[`&`] `{&] [s7; -|double m `= 0;&] -[s7; -|while((i `= co.Next()) < data.GetCount())&] +[s7; -|for(int i `= ii`+`+; i < data.GetCount(); i `= ii`+`+)&] [s7; -|-|m `+`= atof(data`[i`]);&] [s7; -|CoWork`::FinLock();&] [s7; -|sum `+`= m;&] -[s7; `};&] +[s7; `});&] [s7; &] [s7; DUMP(sum);&] [s0; &]