Skip to content

Commit cc0d8e6

Browse files
committed
Mod. optional and regen docs
1 parent 044ece7 commit cc0d8e6

38 files changed

+414
-151
lines changed

Diff for: Doxymain.md

+160
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
[TOC]
2+
3+
# Work In Progress
4+
5+
# Presentation
6+
7+
The Support Class Library (or SCL, formerly named Standard Class Library as a nod to the STL) is a library built on top of the STL and wants to provide tools and interfaces for common problems and patterns in order to make application development easier.
8+
9+
10+
11+
# Parts
12+
13+
## Stream
14+
15+
The stream API is a library that allows lazy evaluation of potentially infinite sequences of data in an easy to write and easy to extend fashion.
16+
17+
18+
19+
### Comparison with pure STL
20+
21+
For instance, a recurrent task is to filter through a collection and execute an action on the filtered elements, let's compare how one would approach this task in both pure STL and using `scl::stream`.
22+
23+
We will assume that the data is initially stored in a `std::vector`.
24+
25+
26+
27+
#### Pure STL solution
28+
29+
```
30+
template <class Predicate, class Action>
31+
void processActionIf(Predicate predicate, Action action){
32+
std::vector<std::shared_ptr<GuiComponent>> components = GUI.getComponents();
33+
for(GuiComponent& component : components){
34+
if(predicate(component))
35+
action(component);
36+
}
37+
}
38+
39+
// OR
40+
41+
template <class Predicate, class Action>
42+
void processActionIf(Predicate predicate, Action action){
43+
std::vector<std::shared_ptr<GuiComponent>> components = GUI.getComponents();
44+
std::vector<std::shared_ptr<GuiComponent>> filtered;
45+
46+
std::copy_if(begin(components), end(components), emplace_back(filtered), predicate);
47+
std::for_each(begin(filtered), end(filtered), action);
48+
}
49+
```
50+
51+
52+
53+
In this simple use-case, using a for-loop reduces the amount of unnecessary copies that the otherwise functional-ish code would make. But things can get quite messy with a for-loop : conditions in conditions, chains of conditions, etc... . With the stream API, we want to get the best of both world : expressive and as efficient as a single for-loop.
54+
55+
56+
57+
#### Stream API
58+
59+
```
60+
template <class Predicate, class Action>
61+
void processActionIf(Predicate predicate, Action action){
62+
streamFrom(GUI.getComponents())
63+
| filter(predicate)
64+
| forEach(action);
65+
}
66+
```
67+
68+
Here we get a lot of advantages :
69+
70+
* Because it has been developped with knowledge of what we encounter in C++, we do not have the "begin&end iterators" issues : we simply pass a container and use it as the data source
71+
* We gain in expressiveness : `filter` expresses more intent than `copy_if` (because `copy_if` was not the actual intent, we used it to filter and use the result afterward)
72+
* We gain in clarity : Loops can get messy, we can mismatch types. Here no type is specified for the components container nor the components themselves (this is true even when there's a lot to process, where loops could get messier)
73+
* We gain in readability : `streamFrom` is where we begin the sequence processing, `|` indicate the start of a new operation, `;` ends the sequence processing
74+
75+
76+
77+
### Design
78+
79+
The library is greatly inspired by rangev3, Rust's `iter`, JS functional methods for arrays, the JS library `sequency` and Java 8's Stream API.
80+
81+
82+
83+
#### Why free functions and operators instead of methods?
84+
85+
In addition to the looks of it, using free functions and operators instead of methods provide one really important selling point : extendability.
86+
87+
88+
89+
With methods, if you want to add an operation for streams you would have to :
90+
91+
* Create a class that inherits from `scl::stream::Stream`
92+
* Add your methods
93+
* Tell the people that want to use your operation to use your class instead of `scl::stream::Stream`
94+
95+
One could argue that with some runtime polymorphism shenanigans provided by the base class we could achieve something similar but it would be painful for the SCL maintainers and probably for the library maintainers.
96+
97+
98+
99+
Using free functions, to add an operation, all you have to do is :
100+
101+
* Create an appropriate stream iterator class (if needed)
102+
* Create a toolbox/type tag (if needed)
103+
* Create the free function
104+
* Create the `operator|` overload for your toolbox/type tag (if needed)
105+
106+
The pain is where it should be, on the library maintainers' side. Honestly, pain is a bit of an exageration.
107+
108+
109+
110+
You can have a look at `filter`/`map` to see how an operator is built from the ground up.
111+
112+
You can have a look at `unique` to see how an operator is built on top of another one.
113+
114+
115+
116+
#### What is the cost?
117+
118+
Let's say you have
119+
120+
```
121+
std::vector<SpecialElement> v = streamFrom(container)
122+
| map(&Element::getSpecialId)
123+
| unique()
124+
| filter(startsWith("s", Case::INSENSITIVE))
125+
| map(+[](const SpecialId& id){ return SpecialHub::from(id, Checks::NONE); })
126+
| pack::toVector();
127+
```
128+
129+
130+
131+
132+
133+
This is roughly equivalent to
134+
135+
```
136+
std::vector<SpecialElement> v;
137+
std::set<SpecialId> tagged;
138+
139+
auto superSpecial = startsWith("s", Case::INSENSITIVE);
140+
for(auto&& e : container){
141+
SpecialId id = e.getSpecialId();
142+
if(tagged.count(id))
143+
continue;
144+
else
145+
tagged.insert(id);
146+
147+
if(!superSpecial(id))
148+
continue;
149+
150+
v.emplace_back(SpecialHub::from(id, Checks::NONE));
151+
}
152+
```
153+
154+
155+
156+
157+
158+
"roughly" because we need to take in account the iterators lifetime as well as the space and state they may use.
159+
160+
Because they are all objects, the state is limited to the lifetime of the iterators/streams and cannot be accessed outside unlike `tagged` and `superSpecial`.

Diff for: doc/html/_doxymain_8md_source.html

+1-1
Large diffs are not rendered by default.

Diff for: doc/html/_either_8h_source.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
<div class="ttc" id="classscl_1_1utils_1_1_either_html_aa4c2436035fcd392065f8d6395000be0"><div class="ttname"><a href="classscl_1_1utils_1_1_either.html#aa4c2436035fcd392065f8d6395000be0">scl::utils::Either::emplaceLeft</a></div><div class="ttdeci">static Either emplaceLeft(Args &amp;&amp;... args)</div><div class="ttdoc">Constructs a Lhs in place. </div><div class="ttdef"><b>Definition:</b> <a href="_either_8h_source.html#l00257">Either.h:257</a></div></div>
8888
<div class="ttc" id="classscl_1_1utils_1_1_either_html_ab001542770e06920b2ce17c11543d9d6"><div class="ttname"><a href="classscl_1_1utils_1_1_either.html#ab001542770e06920b2ce17c11543d9d6">scl::utils::Either::leftVoidVisitor</a></div><div class="ttdeci">static void leftVoidVisitor(const Lhs &amp;lhs)</div><div class="ttdoc">Handy visitor that does nothing on the LHS. </div><div class="ttdef"><b>Definition:</b> <a href="_either_8h_source.html#l00175">Either.h:175</a></div></div>
8989
<div class="ttc" id="classscl_1_1utils_1_1_either_html_aed84432efae83046dd52084b81c5b536"><div class="ttname"><a href="classscl_1_1utils_1_1_either.html#aed84432efae83046dd52084b81c5b536">scl::utils::Either::mapLeftTo</a></div><div class="ttdeci">Either&lt; NewLhs, Rhs &gt; mapLeftTo(Mapper mapper) const</div><div class="ttdoc">Maps the LHS if there&amp;#39;s any. </div><div class="ttdef"><b>Definition:</b> <a href="_either_8h_source.html#l00377">Either.h:377</a></div></div>
90-
<div class="ttc" id="classscl_1_1utils_1_1_optional_html_a9e5a56aae89adf8933e21c65b211ece2"><div class="ttname"><a href="classscl_1_1utils_1_1_optional.html#a9e5a56aae89adf8933e21c65b211ece2">scl::utils::Optional::get</a></div><div class="ttdeci">const value_type &amp; get() const</div><div class="ttdoc">Retrieves the value stored in this Optional&lt;T&gt; </div><div class="ttdef"><b>Definition:</b> <a href="utils_2optional_8h_source.html#l00118">Optional.h:118</a></div></div>
90+
<div class="ttc" id="classscl_1_1utils_1_1_optional_html_a9e5a56aae89adf8933e21c65b211ece2"><div class="ttname"><a href="classscl_1_1utils_1_1_optional.html#a9e5a56aae89adf8933e21c65b211ece2">scl::utils::Optional::get</a></div><div class="ttdeci">const value_type &amp; get() const</div><div class="ttdoc">Retrieves the value stored in this Optional&lt;T&gt; </div><div class="ttdef"><b>Definition:</b> <a href="utils_2optional_8h_source.html#l00120">Optional.h:120</a></div></div>
9191
<div class="ttc" id="classscl_1_1utils_1_1_either_html_aa36b2623d128479cf7834c4676255744"><div class="ttname"><a href="classscl_1_1utils_1_1_either.html#aa36b2623d128479cf7834c4676255744">scl::utils::Either::emplaceRight</a></div><div class="ttdeci">static Either emplaceRight(Args &amp;&amp;... args)</div><div class="ttdoc">Constructs a Rhs in place. </div><div class="ttdef"><b>Definition:</b> <a href="_either_8h_source.html#l00268">Either.h:268</a></div></div>
9292
<div class="ttc" id="classscl_1_1utils_1_1_either_html_a7be53dd97ba40916e017c90785b3c1f8"><div class="ttname"><a href="classscl_1_1utils_1_1_either.html#a7be53dd97ba40916e017c90785b3c1f8">scl::utils::Either::left</a></div><div class="ttdeci">static Either left(L &amp;&amp;lhs)</div><div class="ttdoc">Construct the LHS. </div><div class="ttdef"><b>Definition:</b> <a href="_either_8h_source.html#l00238">Either.h:238</a></div></div>
9393
<div class="ttc" id="structscl_1_1utils_1_1_either_1_1payload__t_html"><div class="ttname"><a href="structscl_1_1utils_1_1_either_1_1payload__t.html">scl::utils::Either::payload_t</a></div><div class="ttdoc">Payload type that encapsulates both alternatives. </div><div class="ttdef"><b>Definition:</b> <a href="_either_8h_source.html#l00050">Either.h:50</a></div></div>

0 commit comments

Comments
 (0)