]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/spirit/doc/karma/complex.qbk
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / spirit / doc / karma / complex.qbk
1 [/==============================================================================
2 Copyright (C) 2001-2011 Hartmut Kaiser
3 Copyright (C) 2001-2011 Joel de Guzman
4
5 Distributed under the Boost Software License, Version 1.0. (See accompanying
6 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 ===============================================================================/]
8
9 [/////////////////////////////////////////////////////////////////////////////]
10 [section:karma_complex Complex - A first more complex generator]
11
12 In this section we will develop a generator for complex numbers, allowing to
13 represent a `std::complex` either as `(real, imag)` (where `real` and `imag`
14 are the real and imaginary parts of the complex number) or as a simple `real`
15 if the imaginary part happens to be equal to zero. This example will highlight
16 the power of __karma__ allowing to combine compile time definition of
17 formatting rules with runtime based decisions which of the rules to apply.
18 Also this time, we're using __boost_phoenix__ to do the semantic actions.
19
20 Our goal is to allow for two different output formats to be applied depending
21 on whether the imaginary part of the complex number is zero or not. Let's write
22 both as a set of alternatives:
23
24 '(' << double_ << ", " << double_ << ')'
25 | double_
26
27 where the first alternative should be used for numbers having a non-zero
28 imaginary part, while the second is for real numbers. Generally, alternatives
29 are tried in the sequence of their definition as long until one of the
30 expressions (as delimited by `'|'`) succeeds. If no generator expression
31 succeeds the whole alternative fails.
32
33 If we left this formatting grammar as is our generator would always choose
34 the first alternative. We need to add some additional rules allowing to make the
35 first alternative fail. So, if the first alternative fails the second one will
36 be chosen instead. The decision about whether to choose the first alternative
37 has to be made at runtime as only then we actually know the value of the
38 imaginary part of the complex number. __karma__ provides us with with a
39 primitive generator `eps()`, which is usable as a semantic predicate. It has
40 the property to 'succeed' generating only if its argument is true (while it
41 never generates any output on its own).
42
43 double imag = ...; // imaginary part
44
45 eps(imag != 0) << '(' << double_ << ", " << double_ << ')'
46 | double_
47
48 If one of the generator elements of a sequence fails the whole sequence will
49 fail. This is exactly what we need, forcing the second alternative to be chosen
50 for complex numbers with imaginary parts equal to zero.
51
52 [import ../../example/karma/complex_number.cpp]
53
54 Now on to the full example, this time with the proper semantic actions (the
55 complete cpp file for this example can be found here:
56 [@../../example/karma/complex_number.cpp complex_number.cpp]).
57
58 We will use the `std::complex` type for this and all subsequent related
59 examples. And here you can see the full code of the generator allowing to
60 output a complex number either as a pair of numbers (if the imaginary part is
61 non-zero) or as a single number (if the complex is a real number):
62
63 [tutorial_karma_complex_number]
64
65 The `double_` generators have this semantic action attached:
66
67 _1 = n
68
69 which passes `n` to the first element of the s generator's attached
70 semantic action. Remember, semantic actions in __karma__ are called
71 before the corresponding generator is invoked and they are expected
72 to provide the generator with the data to be used. The semantic action
73 above assigns the value to be generated (`n`) to the generator (actually,
74 the attribute of `double_`). `_1` is a Phoenix placeholder referring to
75 the attribute of the semantic action's attached generator. If you need
76 more information about semantic actions, you may want to read about them
77 in this section: __karma_actions__.
78
79 These semantic actions are easy to understand but have the unexpected side
80 effect of being slightly less efficient than it could be. In addition they tend
81 to make the formatting grammar less readable. We will see in one of the next
82 sections how it is possible to use other, built-in features of __karma__ to get
83 rid of the semantic actions altogether. When writing your grammars in Spirit
84 you should always try to avoid semantic actions which is often possible.
85 Semantic actions are really powerful tools but grammars tend to be more
86 efficient and readable without them.
87
88 [endsect]
89
90 [/////////////////////////////////////////////////////////////////////////////]
91 [section:karma_easier_complex Complex - Made easier]
92
93 [import ../../example/karma/complex_number_easier.cpp]
94
95 In the previous section we showed how to format a complex number (i.e.
96 a pair of doubles). In this section we will build on this example with the goal
97 to avoid using semantic actions in the format specification. Let's have a look
98 at the resulting code first, trying to understand it afterwards (the full source
99 file for this example can be found here:
100 [@../../example/karma/complex_number_easier.cpp complex_number_easier.cpp]):
101
102 [tutorial_karma_complex_number_easier]
103
104 Let's cover some basic library features first.
105
106 [heading Making Numeric Generators Fail]
107
108 All __karma_numeric__ (such as `double_`, et.al.) take the value to
109 emit from an attached attribute.
110
111 double d = 1.5;
112 generate(out, double_, d); // will emit '1.5' (without the quotes)
113
114 Alternatively, they may be initialized from a literal value. For instance, to
115 emit a constant `1.5` you may write:
116
117 generate(out, double_(1.5)); // will emit '1.5' as well (without the quotes)
118
119 The difference to a simple `1.5` or `lit(1.5)` is that the `double_(1.5)`
120 consumes an attribute if one is available. Additionally, it compares its
121 immediate value to the value of the supplied attribute, and fails if those are
122 not equal.
123
124 double d = 1.5;
125 generate(out, double_(1.5), d); // will emit '1.5' as long as d == 1.5
126
127 This feature, namely to succeed generating only if the attribute matches the
128 immediate value, enables numeric generators to be used to dynamically control
129 the way output is generated.
130
131 [note Quite a few generators will fail if their immediate value is not equal
132 to the supplied attribute. Among those are all __karma_char__ and
133 all [karma_string String Generators]. Generally,
134 all generators having a sibling created by a variant of `lit()` belong
135 into this category.]
136
137 [heading Predicates - The Conditionals for Output Generators]
138
139 In addition to the __karma_eps__ generator mentioned earlier __karma__ provides
140 two special operators enabling dynamic flow control: the
141 __karma_and_predicate__ and the __karma_not_predicate__. The main property of
142 both predicates is to discard all output emitted by the attached generator.
143 This is equivalent to the behavior of predicates used for
144 parsing. There the predicates do not consume any input allowing to look ahead
145 in the input stream. In Karma, the and predicate succeeds as long as its
146 associated generator succeeds, while the not predicate succeeds only if its
147 associated generator fails.
148
149 [note The generator predicates in __karma__ consume an attribute, if
150 available. This makes them behave differently from predicates in __qi__,
151 where they do not expose any attribute. This is because predicates
152 allow to make decisions based on data available only at runtime. While
153 in __qi__ during parsing the decision is made based on looking ahead
154 a few more input tokens, in __karma__ the criteria has to be supplied
155 by the user. The simplest way to do this is by providing an attribute.]
156
157 As an example, the following generator succeeds generating
158
159 double d = 1.0;
160 BOOST_ASSERT(generate(out, &double_(1.0), d)); // succeeds as d == 1.0
161
162 while this one will fail:
163
164 double d = 1.0;
165 BOOST_ASSERT(!generate(out, !double_(1.0), d)); // fails as d == 1.0
166
167 Neither of these will emit any output. The predicates discard everything
168 emitted by the generators to which they are applied.
169
170 [heading Ignoring Supplied Attributes]
171
172 Sometimes it is desirable to 'skip' (i.e. ignore) a provided attribute. This
173 happens for instance in alternative generators, where some of the alternatives
174 need to extract only part of the overall attribute passed to the alternative
175 generator. __karma__ has a special pseudo generator for that: the directive
176 __karma_omit__`[]`. This directive consumes an attribute of the type defined by its
177 embedded generator but it does not emit any output.
178
179 [note The __karma__ __karma_omit__ directive does the 'opposite' of the
180 directive of the same name in __qi__. While the __qi_omit__ in __qi__
181 consumes input without exposing an attribute, its __karma__ counterpart
182 consumes an attribute without emitting any output.
183 ]
184
185 [heading Putting everything together]
186
187 Very similar to our first example earlier we use two alternatives to allow for
188 the two different output formats depending on whether the imaginary part of the
189 complex number is equal to zero or not. The first alternative is executed if the
190 imaginary part is not zero, the second alternative otherwise. This time we make
191 the decision during runtime using the __karma_not_predicate__ combined with the
192 feature of many Karma primitive generators to /fail/ under certain conditions.
193 Here is the first alternative again for your reference:
194
195 !double_(0.0) << '(' << double_ << ", " << double_ << ')'
196
197 The generator `!double_(0.0)` does several things. First, because of the
198 __karma_not_predicate__, it succeeds only if the `double_(0.0)` generator
199 /fails/, making the whole first alternative fail otherwise. Second, the
200 `double_(0.0)` generator succeeds only if the value of its attribute is equal
201 to its immediate parameter (i.e. in this case `0.0`). And third, the
202 not predicate does not emit any output (regardless whether it succeeds or
203 fails), discarding any possibly emitted output from the `double_(0.0)`.
204
205 As we pass the imaginary part of the complex number as the attribute value for
206 the `!double_(0.0)`, the overall first alternative will be chosen only if
207 it is not equal to zero (the `!double_(0.0)` does not fail). That is exactly
208 what we need!
209
210 Now, the second alternative has to emit the real part of the complex
211 number only. In order to simplify the overall grammar we strive to unify the
212 attribute types of all alternatives. As the attribute type exposed by the first
213 alternative is `tuple<double, double, double>`, we need to skip the first and
214 last element of the attribute (remember, we pass the real part as the second
215 attribute element). We achieve this by using the `omit[]` directive:
216
217 omit[double_] << double_ << omit[double_]
218
219 The overall attribute of this expression is `tuple<double, double, double>`,
220 but the `omit[]` 'eats up' the first and the last element. The output emitted
221 by this expression consist of a single generated double representing the second
222 element of the tuple, i.e. the real part of our complex number.
223
224 [important Generally, it is preferable to use generator constructs not
225 requiring semantic actions. The reason is that semantic actions
226 often use constructs like: `double_[_1 = c.real()]`. But this
227 assignment is a real one! The data is in fact /copied/ to the
228 attribute value of the generator attached to the action. On the
229 other hand, grammars without any semantic actions usually don't
230 have to copy the attributes, making them more efficient.]
231
232 [endsect]
233
234 [/////////////////////////////////////////////////////////////////////////////]
235 [section:karma_adapted_complex Complex - Fully Integrated]
236
237 [import ../../example/karma/complex_number_adapt.cpp]
238
239 Until now, we have been working around the fact that `std::complex<>` is not
240 a native __fusion__ sequence. We have not been able to use it with the same
241 simplicity and natural grace of a `fusion::tuple<>` or a similar __fusion__
242 data structure. Fortunately, starting with Boost V1.43 it is possible to
243 adapt any data structure (not only, as before, structures with publicly
244 accessible members) as a __fusion__ sequence. All we have to do is to employ one
245 of the new `BOOST_FUSION_ADAPT_ADT` macros.
246
247 [heading Adapting a Class As a Fusion Sequence]
248
249 Let us start with the code again, following up with the explanations afterwards.
250
251 Wouldn't it be optimal if we could pass our instance of a `std::complex<>`
252 directly to /Karma's/ `generate()` function:
253
254 [tutorial_karma_complex_number_adapt]
255
256 Indeed, this is possible! All we have to supply to make this work is a magic
257 incantation (somewhere in the global namespace):
258
259 [tutorial_karma_complex_number_adapt_class]
260
261 Most of the formatting grammar itself has not changed from the last section. We
262 still utilize a very similar scheme. We have an alternative providing the
263 formatting rules for our both use cases: one for the full complex format and
264 one for complex numbers with a zero imaginary part. But instead of selecting
265 the required alternative by comparing the imaginary part to zero in the grammar
266 we assume to receive a boolean attribute carrying this information:
267
268 &true_ << "(" << double_ << ", " << double_ << ")"
269
270 This reads as: 'if the first (boolean) element of the supplied fusion sequence
271 is `true`, proceed as specified, else select the next alternative'. The next
272 alternative now accounts for the boolean element as well, but is otherwise
273 (almost) unchanged from the last section's example.
274
275 Now it should be clear why our adapt construct above exposes a three element
276 __fusion__ sequence: a boolean and two double values (the real and the
277 imaginary part of the complex number). We want it to match the requirements of
278 our formatting grammar, which expects those exact values. The
279 `BOOST_FUSION_ADAPT_ADT` macro allows us to specify an arbitrary accessor
280 construct, not necessarily limited to just calling a member function of the
281 object instance (represented by `obj` in the context of this macro). This
282 allows us to nicely encapsulate the decision logic into the class adaptation.
283
284 Here is the last new bit of information. If you look closely you realize the
285 second alternative to be 'shorter' than the first one. It consumes only
286 two elements of the supplied fusion sequence: it ignores the boolean and uses
287 the real part of the complex number to generate its output. If there are more
288 elements in our attribute than needed, we now can safely omit them from the
289 grammar (which is a new 'feature' added to __spirit__ in V1.43 as well).
290 Note, we could have written the alternative as
291
292 &false_ << double_
293
294 but this would have been a bit less efficient as we needed to compare the
295 boolean value again, while the final solution provided will just ignore it.
296
297 [endsect]
298