-
Notifications
You must be signed in to change notification settings - Fork 21
/
msetl_example2.cpp
2433 lines (2035 loc) · 107 KB
/
msetl_example2.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Copyright (c) 2015 Noah Lopez
// Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef EXCLUDE_MSETL_EXAMPLE2
#include "msetl_example_defs.h"
#include "msetl_example2.h"
#include "mseregistered.h"
#include "msecregistered.h"
#include "msescope.h"
#include "mseslta.h"
#include "msepoly.h"
#include "msemsearray.h"
#include "msemstdarray.h"
#include "msemsevector.h"
#include "msemstdvector.h"
#include "msemsestring.h"
#include "msemstdstring.h"
#include "mselegacyhelpers.h"
#include "msealgorithm.h"
#include "msethreadlocal.h"
#include "msestaticimmutable.h"
#include "mseoptional.h"
#include "msetuple.h"
#include "msefunctional.h"
#include <iostream>
#include <sstream>
#ifdef _MSC_VER
#pragma warning( push )
#pragma warning( disable : 4100 4456 4189 4702 )
#endif /*_MSC_VER*/
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmissing-braces"
#pragma clang diagnostic ignored "-Wtautological-compare"
#pragma clang diagnostic ignored "-Wunused-variable"
#pragma clang diagnostic ignored "-Wunused-function"
#pragma clang diagnostic ignored "-Wunused-local-typedefs"
#pragma clang diagnostic ignored "-Wunused-but-set-variable"
#else /*__clang__*/
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#endif /*__GNUC__*/
#endif /*__clang__*/
class J {
public:
template<typename _TParam>
static auto foo10(_TParam param) {
_TParam l_obj = param;
auto ret_ptr = &l_obj;
/* ret_ptr may be a smart pointer if the 'operator&' is overloaded.*/
/* If ret_ptr is a scope pointer (or native pointer) it would be unsafe to return it. In those cases the
'mse::return_value(ret_ptr)' expression will induce a compile error. */
/* Functions that could return a scope type need to wrap their return value with the return_value() function. */
return mse::return_value(ret_ptr);
}
template<class _TRASection>
static void foo13(_TRASection ra_section) {
for (typename _TRASection::size_type i = 0; i < ra_section.size(); i += 1) {
ra_section[i] = 0;
}
}
template<class _TRAConstSection>
static int foo14(_TRAConstSection const_ra_section) {
int retval = 0;
for (typename _TRAConstSection::size_type i = 0; i < const_ra_section.size(); i += 1) {
retval += const_ra_section[i];
}
return retval;
}
template<class _TRAConstSection>
static int foo15(_TRAConstSection const_ra_section) {
int retval = 0;
for (const auto& const_item : const_ra_section) {
retval += const_item;
}
return retval;
}
/* Remember that these functions will have implicit/elided lifetime annotations applied to their parameters. */
template<class _TRASection>
static void foo13lta(_TRASection ra_section) {
for (typename _TRASection::size_type i = 0; i < ra_section.size(); i += 1) {
ra_section[i] = ra_section[0];
}
}
template<class _TRAConstSection>
static int foo14lta(_TRAConstSection const_ra_section) {
int retval = 0;
for (typename _TRAConstSection::size_type i = 0; i < const_ra_section.size(); i += 1) {
retval += *(const_ra_section[i]);
}
return retval;
}
template<class _TRAConstSection>
static int foo15lta(_TRAConstSection const_ra_section) {
int retval = 0;
for (const auto& const_item : const_ra_section) {
retval += *const_item;
}
return retval;
}
/* This function will be used to demonstrate using rsv::as_an_fparam() to enable template functions to accept scope
random access sections that reference temporary objects. */
template<class _TRASection1, class _TRASection2>
static bool second_is_longer(const _TRASection1& xscope_ra_csection1, const _TRASection2& xscope_ra_csection2) {
auto l_xscope_ra_csection1 = mse::rsv::as_an_fparam(xscope_ra_csection1);
auto l_xscope_ra_csection2 = mse::rsv::as_an_fparam(xscope_ra_csection2);
return (l_xscope_ra_csection1.size() > l_xscope_ra_csection2.size()) ? false : true;
}
#ifdef MSE_HAS_CXX17
/* While not encouraging their use, this is how you might declare an immutable static member (in C++17 and later). */
inline MSE_DECLARE_STATIC_IMMUTABLE(mse::nii_string) sm_simm_string = "abc";
#endif // MSE_HAS_CXX17
};
MSE_DECLARE_THREAD_LOCAL_GLOBAL(mse::mstd::string) tlg_string1 = "some text";
MSE_RSV_DECLARE_GLOBAL_IMMUTABLE(mse::nii_string) gimm_string1 = "some text";
void msetl_example2() {
{
/**********************/
/* mtnii_vector<> */
/**********************/
/* mtnii_vector<> is a safe vector that is eligible to be (safely) shared between asynchronous threads. Note that
fixed-size vectors (like xscope_borrowing_fixed_nii_vector<>) are also eligible to be shared between asynchronous
threads and are generally preferred when suitable. */
typedef mse::mtnii_vector<mse::nii_string> mtnii_vector1_t;
mse::TRegisteredObj<mtnii_vector1_t> rg_vo1;
for (size_t i = 0; i < 5; i += 1) {
rg_vo1.push_back("some text");
}
mse::TRegisteredPointer<mtnii_vector1_t> vo1_regptr1 = &rg_vo1;
/* mtnii_vector<> does not have a begin() member function that returns an "implicit" iterator. You can obtain an
iterator using the make_begin_iterator() et al. functions, which take a (safe) pointer to the container. */
auto iter1 = mse::make_begin_iterator(vo1_regptr1);
auto citer1 = mse::make_end_const_iterator(vo1_regptr1);
citer1 = iter1;
rg_vo1.emplace(vo1_regptr1, citer1, "some other text");
rg_vo1.insert(vo1_regptr1, citer1, "some other text");
mse::nii_string str1 = "some other text";
rg_vo1.insert(vo1_regptr1, citer1, str1);
class A {
public:
A() {}
int m_i = 0;
};
/* Here we're declaring that A can be safely shared between asynchronous threads. */
typedef mse::rsv::TAsyncShareableAndPassableObj<A> shareable_A_t;
/* When the element type of an mtnii_vector<> is marked as "async shareable", the mtnii_vector<> itself is
(automatically) marked as async shareable as well and can be safely shared between asynchronous threads
using "access requesters". */
auto access_requester1 = mse::make_asyncsharedv2readwrite<mse::mtnii_vector<shareable_A_t>>();
auto access_requester2 = mse::make_asyncsharedv2readwrite<mtnii_vector1_t>();
/* If the element type of an mtnii_vector<> is not marked as "async shareable", then neither is the
mtnii_vector<> itself. So attempting to create an "access requester" using it would result in a compile
error. */
//auto access_requester3 = mse::make_asyncsharedv2readwrite<mse::mtnii_vector<A>>();
//auto access_requester4 = mse::make_asyncsharedv2readwrite<mse::mtnii_vector<mse::mstd::string>>();
typedef mse::mstd::vector<mse::nii_string> vector1_t;
vector1_t vo2 = { "a", "b", "c" };
/* mstd::vector<>s, for example, are not safely shareable between threads. But if its element type is
safely shareable, then the contents of the mse::mstd::vector<>, can be swapped with a corresponding
shareable mtnii_vector<>. Note that vector swaps are intrinsically fast operations. */
std::swap(vo2, *(access_requester2.writelock_ptr()));
{
/* If the vector is declared as a "scope" object (which basically indicates that it is declared
on the stack), then you can use "scope" iterators. While there are limitations on when they can
be used, scope iterators would be the preferred iterator type where performance is a priority
as they don't require extra run-time overhead to ensure that the vector has not been prematurely
deallocated. */
/* Here we're declaring a vector as a scope object. */
mse::TXScopeObj<mse::mtnii_vector<int> > vector1_xscpobj = mse::mtnii_vector<int>{ 1, 2, 3 };
{
/* Here we're obtaining scope iterators to the vector. */
auto xscp_iter1 = mse::make_xscope_begin_iterator(&vector1_xscpobj);
auto xscp_iter2 = mse::make_xscope_end_iterator(&vector1_xscpobj);
std::sort(xscp_iter1, xscp_iter2);
auto xscp_citer3 = mse::make_xscope_begin_const_iterator(&vector1_xscpobj);
xscp_citer3 = xscp_iter1;
xscp_citer3 = mse::make_xscope_begin_const_iterator(&vector1_xscpobj);
xscp_citer3 += 2;
auto res1 = *xscp_citer3;
auto res2 = xscp_citer3[0];
/* Note that scope iterators to vectors (and other dynamic containers), "lock the structure" of the container
so that, for example, it cannot be resized. This allows us to obtain a scope pointer to the (lvalue) iterator's
target element. */
auto xscp_ptr1 = mse::xscope_pointer(xscp_citer3);
auto res3 = *xscp_ptr1;
}
/* After all the scope pointers have gone out of scope, you may again perform operations that affect the container's
"structure" (i.e. size or capacity). */
vector1_xscpobj.push_back(4);
}
}
{
/**********************/
/* stnii_vector<> */
/**********************/
/* stnii_vector<> is just a version of mtnii_vector<> that is not eligible to be shared between threads (and has a
little less overhead as a result). Though when suitable, using nii_vector<> and xscope_borrowing_fixed_nii_vector<>
is generally preferred. */
mse::TXScopeObj<mse::stnii_vector<int> > vector1_xscpobj = mse::stnii_vector<int>{ 1, 2, 3 };
{
mse::TXScopeFixedConstPointer<mse::stnii_vector<int> > xscptr = &vector1_xscpobj;
auto xscp_citer1 = mse::make_xscope_begin_const_iterator(xscptr);
xscp_citer1 += 2;
auto xscp_cptr1 = mse::xscope_const_pointer(xscp_citer1);
auto res1 = *xscp_cptr1;
}
vector1_xscpobj.push_back(4);
/* stnii_vector<>s can be (efficiently) swapped with mtnii_vector<>s. */
auto mtniiv1 = mse::mtnii_vector<int>();
std::swap(vector1_xscpobj, mtniiv1);
/* Or mstd::vector<>s. */
auto mstdv1 = mse::mstd::vector<int>();
std::swap(vector1_xscpobj, mstdv1);
}
{
/********************/
/* nii_vector<> */
/********************/
/* nii_vector<> is another safe vector that is eligible to be (safely) shared between asynchronous threads. It
doesn't use a (costly) thread-safe (atomic) "structure locking" mechanism like mse::mtnii_vector<> does, but
therefore it doesn't supports "structure locking" (and therefore obtaining a scope pointer to an element) via
its scope const iterators, only its scope non-const iterators. */
typedef mse::nii_vector<mse::nii_string> nii_vector1_t;
mse::TRegisteredObj<nii_vector1_t> rg_vo1;
for (size_t i = 0; i < 5; i += 1) {
rg_vo1.push_back("some text");
}
mse::TRegisteredPointer<nii_vector1_t> vo1_regptr1 = &rg_vo1;
/* nii_vector<> does not have a begin() member function that returns an "implicit" iterator. You can obtain an
iterator using the make_begin_iterator() et al. functions, which take a (safe) pointer to the container. */
auto iter1 = mse::make_begin_iterator(vo1_regptr1);
auto citer1 = mse::make_end_const_iterator(vo1_regptr1);
citer1 = iter1;
rg_vo1.emplace(vo1_regptr1, citer1, "some other text");
rg_vo1.insert(vo1_regptr1, citer1, "some other text");
mse::nii_string str1 = "some other text";
rg_vo1.insert(vo1_regptr1, citer1, str1);
class A {
public:
A() {}
int m_i = 0;
};
/* Here we're declaring that A can be safely shared between asynchronous threads. */
typedef mse::rsv::TAsyncShareableAndPassableObj<A> shareable_A_t;
/* When the element type of an nii_vector<> is marked as "async shareable", the nii_vector<> itself is
(automatically) marked as async shareable as well and can be safely shared between asynchronous threads
using "access requesters". */
auto access_requester1 = mse::make_asyncsharedv2readwrite<mse::nii_vector<shareable_A_t>>();
auto access_requester2 = mse::make_asyncsharedv2readwrite<nii_vector1_t>();
/* If the element type of an nii_vector<> is not marked as "async shareable", then neither is the
nii_vector<> itself. So attempting to create an "access requester" using it would result in a compile
error. */
//auto access_requester3 = mse::make_asyncsharedv2readwrite<mse::nii_vector<A>>();
//auto access_requester4 = mse::make_asyncsharedv2readwrite<mse::nii_vector<mse::mstd::string>>();
typedef mse::mstd::vector<mse::nii_string> vector1_t;
vector1_t vo2 = { "a", "b", "c" };
/* mstd::vector<>s, for example, are not safely shareable between threads. But if its element type is
safely shareable, then the contents of the mse::mstd::vector<>, can be swapped with a corresponding
shareable nii_vector<>. Note that vector swaps are intrinsically fast operations. */
std::swap(vo2, *(access_requester2.writelock_ptr()));
{
/* If the vector is declared as a "scope" object (which basically indicates that it is declared
on the stack), then you can use "scope" iterators. While there are limitations on when they can
be used, scope iterators would be the preferred iterator type where performance is a priority
as they don't require extra run-time overhead to ensure that the vector has not been prematurely
deallocated. */
/* Here we're declaring a vector as a scope object. */
mse::TXScopeObj<mse::nii_vector<int> > vector1_xscpobj = mse::nii_vector<int>{ 1, 2, 3 };
{
/* Here we're obtaining a scope iterator to the vector. */
auto xscp_iter1 = mse::make_xscope_begin_iterator(&vector1_xscpobj);
auto xscp_iter2 = mse::make_xscope_end_iterator(&vector1_xscpobj);
std::sort(xscp_iter1, xscp_iter2);
/* Note that nii_vector<>'s scope non-const iterators "lock the structure" of the container so that, for
example, it cannot be resized. This allows us to obtain a scope pointer to the (lvalue) iterator's target
element. */
auto xscp_ptr1 = mse::xscope_pointer(xscp_iter1);
auto res3 = *xscp_ptr1;
auto xscp_citer3 = mse::make_xscope_begin_const_iterator(&vector1_xscpobj);
xscp_citer3 = xscp_iter1;
xscp_citer3 = mse::make_xscope_begin_const_iterator(&vector1_xscpobj);
xscp_citer3 += 2;
auto res1 = *xscp_citer3;
auto res2 = xscp_citer3[0];
}
/* After all the scope pointers have gone out of scope, you may again perform operations that affect the container's
"structure" (i.e. size or capacity). */
vector1_xscpobj.push_back(4);
}
{
/* Unfortunately, you cannot obtain a direct scope const pointer to an nii_vector<> element from a scope const
pointer to the nii_vector<>. (nii_vector<> is the only one of the library's vectors that has this shortcoming.)
However, for vectors that are access controlled with an "exclusive writer" access policy, you can use an
"exclusive writer" const pointer to obtain a direct scope const pointer to a vector element. */
auto xs_ew_niivec1 = mse::make_xscope(mse::make_exclusive_writer(mse::nii_vector<int>{ 1, 2, 3 }));
// which can also be written as:
// mse::TXScopeObj<mse::TExclusiveWriterObj<mse::nii_vector<int> > > xs_ew_niivec1 = mse::nii_vector<int>{ 1, 2, 3 };
{
auto xs_ew_cptr1 = mse::make_xscope_access_controlled_const_pointer(xs_ew_niivec1);
/* The following scope iterator is of a type that reflects that it was constructed from an "exclusive writer"
const pointer. */
auto xs_citer1 = mse::make_xscope_begin_const_iterator(xs_ew_cptr1);
xs_citer1 += 2;
/* We can obtain a (zero-overhead) scope pointer from the (lvalue) iterator. */
auto xs_cptr1 = mse::xscope_const_pointer(xs_citer1);
auto val1 = *xs_cptr1;
}
/* Once the "access controlled const pointer" no longer exists, we can modify the vector again (via "access controlled
(non-const) pointer") */
mse::push_back(mse::make_xscope_access_controlled_pointer(xs_ew_niivec1), 4);
}
}
{
/**************************/
/* fixed_nii_vector<> */
/**************************/
/* A fixed_nii_vector<> is basically like an nii_array<> (i.e. not resizable) whose size is specified at
construction (rather than at compile-time). */
typedef mse::fixed_nii_vector<mse::nii_string> fixed_nii_vector1_t;
mse::TRegisteredObj<fixed_nii_vector1_t> rg_vo1{ mse::nii_string{"abc"}, mse::nii_string{"def"} };
mse::TRegisteredPointer<fixed_nii_vector1_t> vo1_regptr1 = &rg_vo1;
/* fixed_nii_vector<> does not have a begin() member function that returns an "implicit" iterator. You can obtain an
iterator using the make_begin_iterator() et al. functions, which take a (safe) pointer to the container. */
auto iter1 = mse::make_begin_iterator(vo1_regptr1);
auto citer1 = mse::make_end_const_iterator(vo1_regptr1);
citer1 = iter1;
/* fixed_nii_vector<>s can be constructed from other (resizeable) vector types */
auto nvec1 = mse::nii_vector<int>{ 1, 2, 3 };
mse::fixed_nii_vector<int> fixed_nvec1(nvec1);
assert(fixed_nvec1.size() == nvec1.size());
mse::fixed_nii_vector<int> fixed_nvec2(mse::mstd::vector<int>{ 1, 2 });
class A {
public:
A() {}
int m_i = 0;
};
/* Here we're declaring that A can be safely shared between asynchronous threads. */
typedef mse::rsv::TAsyncShareableAndPassableObj<A> shareable_A_t;
/* When the element type of an fixed_nii_vector<> is marked as "async shareable", the fixed_nii_vector<> itself is
(automatically) marked as async shareable as well and can be safely shared between asynchronous threads
using "access requesters". */
auto access_requester1 = mse::make_asyncsharedv2readwrite<mse::fixed_nii_vector<shareable_A_t>>();
auto access_requester2 = mse::make_asyncsharedv2readwrite<fixed_nii_vector1_t>();
/* If the element type of an fixed_nii_vector<> is not marked as "async shareable", then neither is the
fixed_nii_vector<> itself. So attempting to create an "access requester" using it would result in a compile
error. */
//auto access_requester3 = mse::make_asyncsharedv2readwrite<mse::fixed_nii_vector<A>>();
//auto access_requester4 = mse::make_asyncsharedv2readwrite<mse::fixed_nii_vector<mse::mstd::string>>();
{
/* If the vector is declared as a "scope" object (which basically indicates that it is declared
on the stack), then you can use "scope" iterators. While there are limitations on when they can
be used, scope iterators would be the preferred iterator type where performance is a priority
as they don't require extra run-time overhead to ensure that the vector has not been prematurely
deallocated. */
/* Here we're declaring a fixed vector as a scope object. */
mse::TXScopeObj<mse::fixed_nii_vector<int> > vector1_xscpobj{ 1, 2, 3 };
{
/* Here we're obtaining a scope iterator to the vector. */
auto xscp_iter1 = mse::make_xscope_begin_iterator(&vector1_xscpobj);
auto xscp_iter2 = mse::make_xscope_end_iterator(&vector1_xscpobj);
std::sort(xscp_iter1, xscp_iter2);
/* Here we're obtaining a scope pointer from a scope iterator. */
auto xscp_ptr1 = mse::xscope_pointer(xscp_iter1);
auto res3 = *xscp_ptr1;
auto xscp_citer3 = mse::make_xscope_begin_const_iterator(&vector1_xscpobj);
xscp_citer3 = xscp_iter1;
xscp_citer3 = mse::make_xscope_begin_const_iterator(&vector1_xscpobj);
xscp_citer3 += 2;
auto res1 = *xscp_citer3;
auto res2 = xscp_citer3[0];
}
}
}
{
/*******************************************/
/* xscope_borrowing_fixed_nii_vector<> */
/*******************************************/
/* xscope_borrowing_fixed_nii_vector<> is a kind of xscope_fixed_nii_vector<> that, at construction, "borrows" (or "takes"
by moving) the contents of a specified existing (scope object) vector, then, upon destruction "returns" the (possibly
modified) contents back to the original owner. */
auto xs_nii_vector1_xscpobj = mse::make_xscope(mse::nii_vector<int>{ 1, 2, 3 });
/* First we demonstrate some resizing operations on the nii_vector<>. */
/* Note that the standard emplace(), insert() and erase() member functions return an iterator. Since nii_vector<> doesn't
support "implicit" iterators (i.e. iterators generated from the native "this" pointer) those operations are provided by
free functions that take an explicit (safe) "this" pointer used to generate and return an explicit iterator. */
mse::push_back(&xs_nii_vector1_xscpobj, 4/*value*/);
mse::erase(&xs_nii_vector1_xscpobj, 2/*position index*/);
mse::insert(&xs_nii_vector1_xscpobj, 1/*position index*/, 5/*value*/);
mse::insert(&xs_nii_vector1_xscpobj, 0/*position index*/, { 6, 7, 8 }/*value*/);
mse::emplace(&xs_nii_vector1_xscpobj, 2/*position index*/, 9/*value*/);
const auto fnii_vector1_expected = mse::fixed_nii_vector<int>{ 6, 7, 9, 8, 1, 5, 2, 4 };
assert(fnii_vector1_expected == mse::make_xscope_borrowing_fixed_nii_vector(&xs_nii_vector1_xscpobj));
/* Constructing a xscope_borrowing_fixed_nii_vector<> requires a (non-const) scope pointer to an eligible vector. */
auto xs_bf_nii_vector1_xscpobj = mse::make_xscope_borrowing_fixed_nii_vector(&xs_nii_vector1_xscpobj);
{
/* Here we're obtaining a scope iterator to the fixed vector. */
auto xscp_iter1 = mse::make_xscope_begin_iterator(&xs_bf_nii_vector1_xscpobj);
auto xscp_iter2 = mse::make_xscope_end_iterator(&xs_bf_nii_vector1_xscpobj);
std::sort(xscp_iter1, xscp_iter2);
/* Here we're obtaining a scope pointer from a scope iterator. */
auto xscp_ptr1 = mse::xscope_pointer(xscp_iter1);
auto res3 = *xscp_ptr1;
*xscp_ptr1 = 7;
auto xscp_citer3 = mse::make_xscope_begin_const_iterator(&xs_bf_nii_vector1_xscpobj);
xscp_citer3 = xscp_iter1;
xscp_citer3 = mse::make_xscope_begin_const_iterator(&xs_bf_nii_vector1_xscpobj);
xscp_citer3 += 2;
auto res1 = *xscp_citer3;
auto res2 = xscp_citer3[0];
}
class A {
public:
A() {}
int m_i = 0;
};
/* Here we're declaring that A can be safely shared between asynchronous threads. */
typedef mse::rsv::TAsyncShareableAndPassableObj<A> shareable_A_t;
/* When the element type of an xscope_borrowing_fixed_nii_vector<> is marked as "async shareable", the
xscope_borrowing_fixed_nii_vector<> itself is (automatically) marked as async shareable as well and can be safely
shared between asynchronous threads using "access requesters". */
auto xs_shareable_nii_vector1 = mse::make_xscope(mse::nii_vector<shareable_A_t>{});
mse::TXScopeObj<mse::TXScopeAccessControlledObj<mse::xscope_borrowing_fixed_nii_vector<mse::nii_vector<shareable_A_t> > > > xs_aco_bf_nii_vector1(&xs_shareable_nii_vector1);
// which can also be written as
// auto xs_aco_bf_nii_vector1 = mse::make_xscope(mse::make_xscope_access_controlled(mse::xscope_borrowing_fixed_nii_vector<mse::nii_vector<shareable_A_t> >(&xs_shareable_nii_vector1)));
auto xs_access_requester1 = mse::make_xscope_asyncsharedv2acoreadwrite(&xs_aco_bf_nii_vector1);
auto xs_shareable_nii_vector2 = mse::make_xscope(mse::nii_vector<mse::nii_string>{ "abc", "def" });
mse::TXScopeObj<mse::TXScopeAccessControlledObj<mse::xscope_borrowing_fixed_nii_vector<mse::nii_vector<mse::nii_string> > > > xs_aco_bf_nii_vector2(&xs_shareable_nii_vector2);
// which can also be written as
// auto xs_aco_bf_nii_vector1 = mse::make_xscope(mse::make_xscope_access_controlled(mse::xscope_borrowing_fixed_nii_vector<mse::nii_vector<mse::nii_string> >(&xs_shareable_nii_vector2)));
auto xs_access_requester2 = mse::make_xscope_asyncsharedv2acoreadwrite(&xs_aco_bf_nii_vector2);
auto xs_shareable_nii_vector3 = mse::make_xscope(mse::nii_vector<A>{});
/* If the element type of an xscope_borrowing_fixed_nii_vector<> is not marked as "async shareable", then neither is the
xscope_borrowing_fixed_nii_vector<> itself. So attempting to create an "access controlled object" using it would result in
a compile error. */
//auto xs_aco_bf_nii_vector3 = mse::make_xscope(mse::make_xscope_access_controlled(mse::make_xscope_borrowing_fixed_nii_vector(&xs_shareable_nii_vector3)));
//auto xs_access_requester3 = mse::make_xscope_asyncsharedv2acoreadwrite(&xs_aco_bf_nii_vector3);
}
{
/*******************/
/* Poly pointers */
/*******************/
/* Poly pointers are "chameleon" (or "type-erasing") pointers that can be constructed from, and retain
the safety features of multiple different pointer types in this library. If you'd like your function
to be able to take different types of safe pointer parameters, you can "templatize" your function, or
alternatively, you can declare your pointer parameters as poly pointers. */
class A {
public:
A() {}
A(std::string x) : b(x) {}
virtual ~A() {}
std::string b = "some text ";
};
class D : public A {
public:
D(std::string x) : A(x) {}
};
class B {
public:
static std::string foo1(mse::TXScopePolyPointer<A> ptr) {
std::string retval = ptr->b;
return retval;
}
static std::string foo2(mse::TXScopePolyConstPointer<A> ptr) {
std::string retval = ptr->b;
return retval;
}
static std::string foo3(mse::TXScopePolyPointer<std::string> ptr) {
std::string retval = (*ptr) + (*ptr);
return retval;
}
static std::string foo4(mse::TXScopePolyConstPointer<std::string> ptr) {
std::string retval = (*ptr) + (*ptr);
return retval;
}
};
/* To demonstrate, first we'll declare some objects such that we can obtain safe pointers to those
objects. For better or worse, this library provides a bunch of different safe pointers types. */
mse::TXScopeObj<A> a_scpobj;
auto a_refcptr = mse::make_refcounting<A>();
mse::TRegisteredObj<A> a_regobj;
mse::TCRegisteredObj<A> a_cregobj;
/* Safe iterators are a type of safe pointer too. */
mse::mstd::vector<A> a_mstdvec;
a_mstdvec.resize(1);
auto a_mstdvec_iter = a_mstdvec.begin();
mse::us::msevector<A> a_msevec;
a_msevec.resize(1);
auto a_msevec_ipointer = a_msevec.ibegin();
auto a_msevec_ssiter = a_msevec.ss_begin();
/* And note that safe pointers to member elements need to be wrapped in an mse::TXScopeAnyPointer<> for
mse::TXScopePolyPointer<> to accept them. */
auto b_member_a_refc_anyptr = mse::TXScopeAnyPointer<std::string>(mse::make_pointer_to_member_v2(a_refcptr, &A::b));
auto b_member_a_reg_anyptr = mse::TXScopeAnyPointer<std::string>(mse::make_pointer_to_member_v2(&a_regobj, &A::b));
auto b_member_a_mstdvec_iter_anyptr = mse::TXScopeAnyPointer<std::string>(mse::make_pointer_to_member_v2(a_mstdvec_iter, &A::b));
{
/* All of these safe pointer types happily convert to an mse::TXScopePolyPointer<>. */
auto res_using_scpptr = B::foo1(&a_scpobj);
auto res_using_refcptr = B::foo1(a_refcptr);
auto res_using_regptr = B::foo1(&a_regobj);
auto res_using_cregptr = B::foo1(&a_cregobj);
auto res_using_mstdvec_iter = B::foo1(a_mstdvec_iter);
auto res_using_msevec_ipointer = B::foo1(a_msevec_ipointer);
auto res_using_msevec_ssiter = B::foo1(a_msevec_ssiter);
auto res_using_member_refc_anyptr = B::foo3(b_member_a_refc_anyptr);
auto res_using_member_reg_anyptr = B::foo3(b_member_a_reg_anyptr);
auto res_using_member_mstdvec_iter_anyptr = B::foo3(b_member_a_mstdvec_iter_anyptr);
/* Or an mse::TXScopePolyConstPointer<>. */
auto res_using_scpptr_via_const_poly = B::foo2(&a_scpobj);
auto res_using_refcptr_via_const_poly = B::foo2(a_refcptr);
auto res_using_regptr_via_const_poly = B::foo2(&a_regobj);
auto res_using_cregptr_via_const_poly = B::foo2(&a_cregobj);
auto res_using_mstdvec_iter_via_const_poly = B::foo2(a_mstdvec_iter);
auto res_using_msevec_ipointer_via_const_poly = B::foo2(a_msevec_ipointer);
auto res_using_msevec_ssiter_via_const_poly = B::foo2(a_msevec_ssiter);
auto res_using_member_refc_anyptr_via_const_poly = B::foo4(b_member_a_refc_anyptr);
auto res_using_member_reg_anyptr_via_const_poly = B::foo4(b_member_a_reg_anyptr);
auto res_using_member_mstdvec_iter_anyptr_via_const_poly = B::foo4(b_member_a_mstdvec_iter_anyptr);
}
mse::TNullableAnyPointer<A> nanyptr1;
mse::TNullableAnyPointer<A> nanyptr2(nullptr);
mse::TNullableAnyPointer<A> nanyptr3(a_refcptr);
mse::TAnyPointer<A> anyptr3(a_refcptr);
nanyptr1 = nullptr;
nanyptr1 = 0;
nanyptr1 = NULL;
nanyptr1 = nanyptr2;
nanyptr1 = mse::TNullableAnyPointer<A>(&a_regobj);
nanyptr1 = mse::TNullableAnyPointer<A>(a_refcptr);
auto res_nap1 = *nanyptr1;
mse::self_test::CPolyPtrTest1::s_test1();
int q = 3;
}
{
/*********************************/
/* TAnyRandomAccessIterator<> */
/* & TAnyRandomAccessSection<> */
/*********************************/
/* Like TAnyPointer<>, TAnyRandomAccessIterator<> and TAnyRandomAccessSection<> are polymorphic iterators and
"sections" that can be used to enable functions to take as arguments any type of iterator or section of any
random access container (like an array or vector). */
mse::mstd::array<int, 4> mstd_array1{ 1, 2, 3, 4 };
mse::us::msearray<int, 5> msearray2{ 5, 6, 7, 8, 9 };
mse::mstd::vector<int> mstd_vec1{ 10, 11, 12, 13, 14 };
class B {
public:
static void foo1(mse::TXScopeAnyRandomAccessIterator<int> ra_iter1) {
ra_iter1[1] = 15;
}
static int foo2(mse::TXScopeAnyRandomAccessConstIterator<int> const_ra_iter1) {
const_ra_iter1 += 2;
--const_ra_iter1;
const_ra_iter1--;
return const_ra_iter1[2];
}
static void foo3(mse::TXScopeAnyRandomAccessSection<int> ra_section) {
for (mse::TXScopeAnyRandomAccessSection<int>::size_type i = 0; i < ra_section.size(); i += 1) {
ra_section[i] = 0;
}
}
static int foo4(mse::TXScopeAnyRandomAccessConstSection<int> const_ra_section) {
int retval = 0;
for (mse::TXScopeAnyRandomAccessSection<int>::size_type i = 0; i < const_ra_section.size(); i += 1) {
retval += const_ra_section[i];
}
return retval;
}
static int foo5(mse::TXScopeAnyRandomAccessConstSection<int> const_ra_section) {
int retval = 0;
for (const auto& const_item : const_ra_section) {
retval += const_item;
}
return retval;
}
};
auto mstd_array_iter1 = mstd_array1.begin();
mstd_array_iter1++;
auto res1 = B::foo2(mstd_array_iter1);
B::foo1(mstd_array_iter1);
auto msearray_const_iter2 = msearray2.ss_cbegin();
msearray_const_iter2 += 2;
auto res2 = B::foo2(msearray_const_iter2);
auto res3 = B::foo2(mstd_vec1.cbegin());
B::foo1(++mstd_vec1.begin());
auto res4 = B::foo2(mstd_vec1.begin());
mse::TXScopeAnyRandomAccessIterator<int> ra_iter1 = mstd_vec1.begin();
mse::TXScopeAnyRandomAccessIterator<int> ra_iter2 = mstd_vec1.end();
auto res5 = ra_iter2 - ra_iter1;
ra_iter1 = ra_iter2;
{
std::array<int, 4> std_array1{ 1, 2, 3, 4 };
mse::TXScopeAnyRandomAccessIterator<int> ra_iter1(std_array1.begin());
mse::TXScopeAnyRandomAccessIterator<int> ra_iter2 = std_array1.end();
auto res5 = ra_iter2 - ra_iter1;
ra_iter1 = ra_iter2;
}
mse::TXScopeObj<mse::mstd::array<int, 4> > mstd_array3_scpobj = mse::mstd::array<int, 4>({ 1, 2, 3, 4 });
auto mstd_array_scpiter3 = mse::mstd::make_xscope_begin_iterator(&mstd_array3_scpobj);
//mstd_array_scpiter3 = mstd_array3_scpobj.begin();
++mstd_array_scpiter3;
B::foo1(mstd_array_scpiter3);
mse::TXScopeAnyRandomAccessSection<int> xscp_ra_section1(mstd_array_iter1, 2);
B::foo3(xscp_ra_section1);
mse::TXScopeAnyRandomAccessSection<int> xscp_ra_section2(++mstd_vec1.begin(), 3);
auto res6 = B::foo5(xscp_ra_section2);
B::foo3(xscp_ra_section2);
auto res7 = B::foo4(xscp_ra_section2);
auto xscp_ra_section1_xscp_iter1 = xscp_ra_section1.xscope_begin();
auto xscp_ra_section1_xscp_iter2 = xscp_ra_section1.xscope_end();
auto res8 = xscp_ra_section1_xscp_iter2 - xscp_ra_section1_xscp_iter1;
bool res9 = (xscp_ra_section1_xscp_iter1 < xscp_ra_section1_xscp_iter2);
auto ra_section1 = mse::make_random_access_section(mstd_array_iter1, 2);
B::foo3(ra_section1);
auto ra_const_section2 = mse::make_random_access_const_section(mstd_vec1.cbegin(), 2);
B::foo4(ra_const_section2);
int q = 5;
}
{
/********************************************/
/* TXScopeCSSSXSTERandomAccessIterator<> */
/* & TXScopeCSSSXSTERandomAccessSection<> */
/********************************************/
/* TXScopeCSSSXSTERandomAccessIterator<> and TXScopeCSSSXSTERandomAccessSection<> are "type-erased" template classes
that function much like TXScopeAnyRandomAccessIterator<> and TXScopeAnyRandomAccessSection<> in that they can be
used to enable functions to take as arguments iterators or sections of various container types (like an arrays or
vectors) without making the functions in to template functions. But in this case there are limitations on what types
can be converted. In exchange for these limitations, these types require less overhead. The "CSSSXSTE" part of the
typenames stands for "Contiguous Sequence, Static Structure, XScope, Type-Erased". So the first restriction is that
the target container must be recognized as a "contiguous sequence" (basically an array or vector). It also must be
recognized as having a "static structure". This essentially means that the container cannot be resized. Note that
while vectors support resizing, the ones in the library can be "structure locked" at run-time to ensure that they
are not resized (i.e. have a "static structure") during certain periods. And only the "scope" versions of the
iterators and sections are supported. */
auto xs_mstd_array1 = mse::make_xscope(mse::mstd::array<int, 4>{ 1, 2, 3, 4 });
auto xs_msearray2 = mse::make_xscope(mse::us::msearray<int, 5>{ 5, 6, 7, 8, 9 });
auto xs_mstd_vec1 = mse::make_xscope(mse::mstd::vector<int>{ 10, 11, 12, 13, 14 });
class B {
public:
static void foo1(mse::TXScopeCSSSXSTERandomAccessIterator<int> ra_iter1) {
ra_iter1[1] = 15;
}
static int foo2(mse::TXScopeCSSSXSTERandomAccessConstIterator<int> const_ra_iter1) {
const_ra_iter1 += 2;
--const_ra_iter1;
const_ra_iter1--;
return const_ra_iter1[2];
}
static int foo2b(mse::rsv::TFParam<mse::TXScopeCSSSXSTERandomAccessConstIterator<int> > const_ra_iter1) {
return foo2(const_ra_iter1);
}
#ifndef EXCLUDE_DUE_TO_MSVC2019_INTELLISENSE_BUGS1
static void foo3(mse::TXScopeCSSSXSTERandomAccessSection<int> ra_section) {
for (mse::TXScopeCSSSXSTERandomAccessSection<int>::size_type i = 0; i < ra_section.size(); i += 1) {
ra_section[i] = 0;
}
}
static int foo4(mse::TXScopeCSSSXSTERandomAccessConstSection<int> const_ra_section) {
int retval = 0;
for (mse::TXScopeCSSSXSTERandomAccessSection<int>::size_type i = 0; i < const_ra_section.size(); i += 1) {
retval += const_ra_section[i];
}
return retval;
}
static int foo5(mse::TXScopeCSSSXSTERandomAccessConstSection<int> const_ra_section) {
int retval = 0;
for (const auto& const_item : const_ra_section) {
retval += const_item;
}
return retval;
}
#endif // !EXCLUDE_DUE_TO_MSVC2019_INTELLISENSE_BUGS1
};
auto xs_mstd_array_iter1 = mse::make_xscope_begin_iterator(&xs_mstd_array1);
xs_mstd_array_iter1++;
auto res1 = B::foo2(xs_mstd_array_iter1);
B::foo1(xs_mstd_array_iter1);
auto xs_msearray_const_iter2 = mse::make_xscope_begin_const_iterator(&xs_msearray2);
xs_msearray_const_iter2 += 2;
auto res2 = B::foo2(xs_msearray_const_iter2);
auto xs_mstd_vec1_citer1 = mse::make_xscope_begin_const_iterator(&xs_mstd_vec1);
auto res3 = B::foo2(xs_mstd_vec1_citer1);
/*
Note that attempting to combine the previous two lines into a single expression like so:
auto res3b = B::foo2(mse::make_xscope_begin_const_iterator(&xs_mstd_vec1));
is not supported and would result in a compile error.
In the case of dynamic containers, like vectors and strings, the (scope) iterators can only be converted to
TXScopeCSSSXSTERandomAccessIterator<>s if they are lvalues, not temporaries/rvalues. This is because scope iterators
hold a "structure lock" that prevents the container from being resized. If the scope iterator you're attempting to
convert from is a temporary (rvalue) one, then the structure lock would be just as temporary and it would not be safe
to create a TXScopeCSSSXSTERandomAccessIterator<> that outlives the period when the container is "structure locked".
"Non-resizable" containers, like arrays, do not have the same issue, so this restriction does not apply to their
(scope) iterators.
*/
auto res3c = B::foo2b(mse::make_xscope_begin_const_iterator(&xs_mstd_vec1));
/*
However, note that, unlike B::foo2(), B::foo2b() "annotates" its (non-returnable) parameter with the rsv::TFParam<>
template wrapper. This allows it to accept temporary/rvalue (scope) iterators of dynamic containers. This is safe
because we know that (even temporary) function arguments will outlive their corresponding (non-returnable) parameter
values.
*/
auto xs_mstd_vec1_iter2 = ++mse::make_xscope_begin_iterator(&xs_mstd_vec1);
B::foo1(xs_mstd_vec1_iter2);
auto xs_mstd_vec1_iter1 = mse::make_xscope_begin_iterator(&xs_mstd_vec1);
auto res4 = B::foo2(xs_mstd_vec1_iter1);
auto xs_mstd_vec1_begin_iter1 = mse::make_xscope_begin_iterator(&xs_mstd_vec1);
mse::TXScopeCSSSXSTERandomAccessIterator<int> xs_te_iter1 = xs_mstd_vec1_begin_iter1;
auto xs_mstd_vec1_end_iter1 = mse::make_xscope_end_iterator(&xs_mstd_vec1);
mse::TXScopeCSSSXSTERandomAccessIterator<int> xs_te_iter2 = xs_mstd_vec1_end_iter1;
auto res5 = xs_te_iter2 - xs_te_iter1;
xs_te_iter2 = xs_te_iter1;
{
auto std_array1 = mse::make_xscope(std::array<int, 4>{ 1, 2, 3, 4 });
mse::TXScopeCSSSXSTERandomAccessIterator<int> xs_te_iter1(mse::make_xscope_begin_iterator(&std_array1));
mse::TXScopeCSSSXSTERandomAccessIterator<int> xs_te_iter2 = mse::make_xscope_end_iterator(&std_array1);
auto res5 = xs_te_iter2 - xs_te_iter1;
xs_te_iter1 = xs_te_iter2;
}
mse::TXScopeObj<mse::mstd::array<int, 4> > mstd_array3_scpobj = mse::mstd::array<int, 4>({ 1, 2, 3, 4 });
auto mstd_array_scpiter3 = mse::mstd::make_xscope_begin_iterator(&mstd_array3_scpobj);
++mstd_array_scpiter3;
B::foo1(mstd_array_scpiter3);
#ifndef EXCLUDE_DUE_TO_MSVC2019_INTELLISENSE_BUGS1
mse::TXScopeCSSSXSTERandomAccessSection<int> xscp_ra_section1(xs_mstd_array_iter1++, 2);
B::foo3(xscp_ra_section1);
auto xs_mstd_vec_iter1 = mse::make_xscope_begin_iterator(&xs_mstd_vec1);
mse::TXScopeCSSSXSTERandomAccessSection<int> xscp_ra_section2(++xs_mstd_vec_iter1, 3);
/*
Note that had we instead used the postfix increment operator on the xs_mstd_vec_iter1 argument in the previous line
like so:
mse::TXScopeCSSSXSTERandomAccessSection<int> xscp_ra_section2b(xs_mstd_vec_iter1++, 3);
we would have gotten a compile error. That's because unlike the prefix increment operator, the postfix increment
operator returns a temporary (rvalue) copy of the iterator, and as noted earlier, in the case of dynamic containers,
like vectors and strings, conversion/construction from temporary (rvalue) versions of their iterators could be unsafe
and is not supported.
*/
auto res6 = B::foo5(xscp_ra_section2);
B::foo3(xscp_ra_section2);
auto res7 = B::foo4(xscp_ra_section2);
auto xs_ra_section1 = mse::make_xscope_random_access_section(xs_mstd_array_iter1, 2);
B::foo3(xs_ra_section1);
auto xs_ra_const_section2 = mse::make_xscope_random_access_const_section(mse::make_xscope_begin_const_iterator(&xs_mstd_vec1), 2);
B::foo4(xs_ra_const_section2);
auto nii_array4_scpobj = mse::make_xscope(mse::nii_array<int, 4>{ 1, 2, 3, 4 });
auto xscp_ra_section3 = mse::make_xscope_csssxste_random_access_section(&nii_array4_scpobj);
auto xscp_ra_section1_xscp_iter1 = mse::make_xscope_begin_iterator(xscp_ra_section1);
auto xscp_ra_section1_xscp_iter2 = mse::make_xscope_end_iterator(xscp_ra_section1);
auto res8 = xscp_ra_section1_xscp_iter2 - xscp_ra_section1_xscp_iter1;
bool res9 = (xscp_ra_section1_xscp_iter1 < xscp_ra_section1_xscp_iter2);
mse::for_each_ptr(xscp_ra_section1.begin(), xscp_ra_section1.end(), [](auto item_ptr) { std::cout << (*item_ptr); });
mse::for_each_ptr(xscp_ra_section2.begin(), xscp_ra_section2.end(), [](auto item_ptr) { std::cout << (*item_ptr); });
mse::for_each_ptr(xs_ra_const_section2.begin(), xs_ra_const_section2.end(), [](auto item_ptr) { std::cout << (*item_ptr); });
#endif // !EXCLUDE_DUE_TO_MSVC2019_INTELLISENSE_BUGS1
}
{
/****************/
/* optional<> */
/****************/
{
/* mstd::optional<> is essentially just a safe implementation of std::optional<>. */
auto opt1 = mse::mstd::optional<int>{ 7 };
assert(opt1.has_value());
auto val1 = opt1.value();
}
#ifndef EXCLUDE_DUE_TO_MSVC2019_INTELLISENSE_BUGS1
{
/* You might think of optional<> as a dynamic container like a vector<> that supports a maximum of one element.
So like vectors, directly accessing or referencing the contents of an optional<> is discouraged. Instead
prefer to access the contents via an xscope_borrowing_fixed_optional<>, which is a "non-dynamic" type (i.e. its
element, if present, can be modified, but elements cannot be added or removed), that will "borrow" the contents
of the "dynamic" optional<>. */
auto xs_opt1 = mse::make_xscope(mse::make_optional(mse::mstd::string("abc")));
// which can also be written as
// auto xs_opt1 = mse::TXScopeObj<mse::optional<mse::mstd::string> >("abc");
xs_opt1 = {};
xs_opt1 = mse::mstd::string("def");
{
/* Here we obtain an xscope_borrowing_fixed_optional<> that "borrows" the contents of xs_opt1. */
auto xs_bfopt1 = mse::make_xscope_borrowing_fixed_optional(&xs_opt1);
/* Note that accessing xs_opt1 is prohibited while xs_bfopt1 exists. This restriction is enforced.*/
/* Here we obtain a (safe) pointer to the contained element. */
auto xs_elem_ptr1 = mse::make_xscope_fixed_optional_element_pointer(&xs_bfopt1);
/* We can also then obtain a scope pointer to the contained element. */
auto xs_ptr1 = mse::xscope_pointer(xs_elem_ptr1);
auto val1 = *xs_ptr1;
*xs_ptr1 = mse::mstd::string("ghi");
}
/* After the xscope_borrowing_fixed_optional<> is gone, we can again access our optional<>. */
xs_opt1.reset();
}
#endif // !EXCLUDE_DUE_TO_MSVC2019_INTELLISENSE_BUGS1
{
/* Analogous to mtnii_vector<>, mt_optional<> is a version that is eligible to be shared among threads, at a
cost of slightly higher run-time overhead. When suitable, using optional<> and xscope_borrowing_optional<> is
generally preferred. */
auto opt1_access_requester = mse::make_asyncsharedv2readwrite<mse::mt_optional<mse::nii_string> >("abc");
auto elem_ptr1 = mse::make_optional_element_pointer(opt1_access_requester.writelock_ptr());
auto val1 = *elem_ptr1;
}
#ifndef EXCLUDE_DUE_TO_MSVC2019_INTELLISENSE_BUGS1
{
/* optional<>s can, like any other type, be declared as a scope type (using mse::make_xscope() / mse::TXScopeObj<>).
But they do not support using scope types as their contained element type. It is (intended to be) uncommon to need
such capability. But the library does provide a couple of versions that support it. xscope_mt_optional<> is eligible
to be shared among (scope) threads, while xscope_st_optional<> is not. */
/* Here we're creating a (string) object of scope type. */
auto xs_str1 = mse::make_xscope(mse::mstd::string("abc"));
/* Here we're creating an xscope_st_optional<> object that contains a scope pointer to the (scope) string object.
mstd::optional<>, for example, would not support this. */
auto xsopt1 = mse::make_xscope_st_optional(&xs_str1);
// which can also be written as
// auto xsopt1 = mse::xscope_st_optional<mse::TXScopeFixedPointer<mse::mstd::string> >(&xs_str1);
auto val1 = *(xsopt1.value());
}
{
/* You might think of optional<> as a dynamic container like a vector<> that supports a maximum of one element.
That would make mse::optional<> analogous to mse::nii_vector<>. That is, it is eligible to be shared among
threads while having lower overhead than mt_optional<>, but the trade-off being that you cannot, in general,
obtain a direct scope pointer to the contained element from a const reference to the mse::optional<> container.
But, like nii_vector<>, you can if the mse::optional<> container is declared as an "exclusive writer" object: */
auto xs_ac_opt1 = mse::make_xscope(mse::make_exclusive_writer(mse::optional<mse::nii_string>("abc")));
auto xs_ac_cptr1 = mse::make_xscope_access_controlled_const_pointer(xs_ac_opt1);
auto xs_elem_cptr1 = mse::make_xscope_optional_element_const_pointer(xs_ac_cptr1);
auto xs_ptr1 = mse::xscope_pointer(xs_elem_cptr1);
auto val1 = *xs_ptr1;
}
mse::self_test::COptionalTest1::s_test1();
#endif // EXCLUDE_DUE_TO_MSVC2019_INTELLISENSE_BUGS1
}
{
/***********/
/* any<> */
/***********/
{
/* mstd::any<> is essentially just a safe implementation of std::any<>. */
auto any1 = mse::mstd::any{ 7 };
assert(any1.has_value());
auto val1 = mse::mstd::any_cast<int>(any1);
}
#ifndef EXCLUDE_DUE_TO_MSVC2019_INTELLISENSE_BUGS1
{
/* You might think of `any` as a dynamic container like a vector<> that supports a maximum of one element.
So like vectors, directly accessing or referencing the contents of an `any` is discouraged. Instead
prefer to access the contents via an xscope_borrowing_fixed_any<>, which is a "non-dynamic" type (i.e. its
element, if present, can be modified, but elements cannot be added or removed), that will "borrow" the contents
of the "dynamic" `any`. */
auto xs_any1 = mse::make_xscope(mse::make_any<mse::mstd::string>("abc"));
// which can also be written as
// auto xs_any1 = mse::TXScopeObj<mse::any<mse::mstd::string> >("abc");
xs_any1 = {};
xs_any1 = mse::mstd::string("def");