-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathtutorial.hpp
144 lines (100 loc) · 6.18 KB
/
tutorial.hpp
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
#error DO NOT INCLUDE - DOCUMENTATION PURPOSE ONLY
//==================================================================================================
/**
\page tutorial RABERU 101
@tableofcontents
The **RABERU** library provides a way to define and use named parameters, *i.e* a list of values assigned to
arbitrary keyword-like identifiers, to functions.
It does so by providing:
+ a protocol to define such keywords.
+ a type to process such aggregate of parameters.
+ a `constexpr`-compatible implementation for all of those.
\section tutorial_01 Keyword, Options, Settings
Let's define a small function - `replicate` - that takes a character `c` and an integer `n` as parameters and
return a string containing `c` repeated `n` times. As we want our users to have maximum flexibility, we will
pass those parameters as keyword/value pairs.
@include doc/tutorial01.cpp
Let's decompose this code:
+ First, we define the `replicate` function. It takes two parameters which model
rbr::concepts::option, ensuring the parameters are valid **RABERU** key/value pairs.
+ Those parameters are then turned into an instance of rbr::settings which will provide the interface to query values from the bundle of parameters.
+ We retrieve the value associated to the `"replication"_kw` and `"letter"_kw` keywords.
+ In the `main` function, we call `replicate` by passing key/value pairs. Note that the keys are the exact same identifiers than those used inside the function. Their order is irrelevant.
That's it. The `replicate` function can now takes keywords arguments and as long as the proper keywords are used, it will work as intended.
\section tutorial_02 Flavor of Keywords
\subsection tutorial-keywords Regular keywords
Let's say you want to pass a compile-time unrolling factor to some algorithm.
You can use a regular keyword as seen in the tutorial:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++
auto x = my_algorithm( "unroll"_kw = std::integral_constant<int,4>{});
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This is working but a bit verbose. Another issue can be that documenting the fact
that your functions awaits a `"unroll"_kw` maybe cumbersome.
A nicer way to simplify the user experience is to preemptively defines a keyword variable.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++
inline constexpr auto unroll = "unroll"_kw;
auto x = my_algorithm( unroll = std::integral_constant<int,4>{});
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Slightly terser and far easier to document.
You can also use the rbr::keyword factory that takes an ID and returns a keyword instance
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++
inline constexpr auto unroll = rbr::keyword("unroll"_id);
auto x = my_algorithm( unroll = std::integral_constant<int,4>{});
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\subsection tutorial-flags Flags
Sometimes, you just want to check if a given parameter has been passed but you don't really care about an associated value. Such keyword parameters are **flags**, carrying information about their sole presence without the need ot be bound to a value.
They work in a similar way than regular keyword parameters but use the `_fl` user-defined literal
ior the rbr::flag factory. Their value can be retrieved via rbr::settings::operator[]. If present, the value returned is `std::true_type`, otherwise `std::false_type` is returned.
@include doc/tutorial02.cpp
\subsection tutorial-checked Checked keywords
Regular keywords accept value of any types. Flag keyword implicitly behaves as boolean parameters.
What if you need to have a keyword accepting values of a specific type ? Or, in more complex
context, what if you need a keyword accepting values which types satisfy an arbitrary set of
constraints ?
To do so, we'll need to use the rbr::keyword factory function that
accepts an optional template parameter. If this template parameter is a type,
the keyword is setup to only accept value of this exact type.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++
using namespace rbr::literals;
// color can only accept unsigned 32 bits integer
auto color = rbr::keyword<std::uint32_t>("color"_id);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If this template parameter is a unary template meta-function `F`, the keyword is setup to only
accept value which type satisfy `F<T>::value == true`.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++
using namespace rbr::literals;
template<typename T> struct large_type
{
static constexpr auto value = sizeof(T) >= 4;
};
// entropy can only accept types of at least 32 bits
inline constexpr auto entropy = rbr::keyword<large_type>( "entropy"_id);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\section tutorial_03 Settings
Another important **RABERU** component is rbr::settings. It aggregates key/value pairs in a way their
exploitation is simplified. rbr::settings provides functions for retrieving value from keywords,
inspect the stored keywords and more.
\subsection tutorial-settings Defining a Settings
rbr::settings can be directly constructed from an arbitrary list of options, ie values bound to
a keyword. Once constructed, its operator[] can be used to fetch the value of a given keyword.
@include doc/tutorial03.cpp
\subsection tutorial-stream Stream insertion
rbr::settings can be streamed to display the list of keyword/value pairs it contains
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++
#include <raberu/raberu.hpp>
#include <iostream>
int main()
{
using namespace rbr::literals;
auto values = rbr::settings("size"_kw = 75ULL, "transparent"_fl, "value"_kw = 7.7f);
std::cout << values << "\n";
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The expected output should be:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'size' : 75 (long long unsigned int)
'transparent' : 1 (std::integral_constant<bool, true>)
'value' : 7.7 (float)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**/
//==================================================================================================