]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | [/ |
2 | (C) Copyright Edward Diener 2011-2015 | |
3 | Distributed under the Boost Software License, Version 1.0. | |
4 | (See accompanying file LICENSE_1_0.txt or copy at | |
5 | http://www.boost.org/LICENSE_1_0.txt). | |
6 | ] | |
7 | ||
8 | [section:vmd_modifiers_return_type Return type modifiers] | |
9 | ||
10 | A number of macros are capable of returning the type of | |
11 | data as a v-type rather than, or along with, the | |
12 | data itself. The most obvious of these is BOOST_VMD_GET_TYPE | |
13 | which generically returns the type of the input. | |
14 | ||
15 | Return type modifiers turn on, turn off, or change | |
16 | the type of the data returned in some way. | |
17 | ||
18 | These modifiers are: | |
19 | ||
20 | * BOOST_VMD_RETURN_NO_TYPE, do not return the type of data. | |
21 | * BOOST_VMD_RETURN_TYPE, return the type of data parsing any tuple-like | |
22 | syntactical construct as its most specific type. This means that any | |
23 | tuple-like construct is parsed first as a possible list, next as a | |
24 | possible array if it is not a list, and finally as a tuple if it is not a | |
25 | list or an array. | |
26 | * BOOST_VMD_RETURN_TYPE_LIST, parse any tuple-like syntactical construct | |
27 | first as a possible list and only then as a tuple if it is not a list. | |
28 | * BOOST_VMD_RETURN_TYPE_ARRAY, parse any tuple-like syntactical construct | |
29 | first as a possible array and only then as a tuple if it is not an array. | |
30 | * BOOST_VMD_RETURN_TYPE_TUPLE, parse any tuple-like syntactical construct | |
31 | only as a tuple. | |
32 | ||
33 | When VMD parses input generically it must determine the type of each data | |
34 | element of the input. For nearly all of the VMD data types this is never | |
35 | a problem. For the array or list data types this can be a problem, as | |
36 | explained when discussing parsing arrays and lists respectively using the | |
37 | specific macros BOOST_VMD_IS_ARRAY and BOOST_VMD_IS_LIST. The problem is | |
38 | that a valid tuple can be an invalid list or an invalid array, whose | |
39 | parsing as the more specific type will lead to UB. | |
40 | Because of this when VMD parses input generically, | |
41 | and only the data of an element is needed to continue parsing correctly, | |
42 | it parses all tuple-like data as a tuple and never as a list or an array. | |
43 | ||
44 | When VMD parses input generically, and the type of the data is required | |
45 | in some way as part of the return of a macro, VMD by default parses for | |
46 | the most specific type of each data element in order to return the most | |
47 | accurate type. In this situation by default the | |
48 | BOOST_VMD_RETURN_TYPE modifier is internally in effect without having | |
49 | to be specified. | |
50 | ||
51 | If more than one of the return type modifiers are specified as optional | |
52 | parameters the last one specified is in effect. | |
53 | ||
54 | [heading Usage with BOOST_VMD_GET_TYPE] | |
55 | ||
56 | The only macro in which VMD without the use of modifiers is being asked | |
57 | to return the type of data is BOOST_VMD_GET_TYPE. For this macro | |
58 | the BOOST_VMD_RETURN_TYPE modifier is internally in effect so if | |
59 | no return type modifiers are input as optional parameters BOOST_VMD_GET_TYPE | |
60 | looks for the most specific type. | |
61 | ||
62 | For the BOOST_VMD_GET_TYPE macro the optional return type modifier | |
63 | BOOST_VMD_RETURN_NO_TYPE, if specified, is always ignored since the purpose of | |
64 | BOOST_VMD_GET_TYPE is solely to return the v-type. | |
65 | ||
66 | Let's look at how this works with BOOST_VMD_GET_TYPE by specifying VMD sequences | |
67 | that have tuples which may or may not be valid lists or arrays. | |
68 | ||
69 | #include <boost/vmd/get_type.hpp> | |
70 | ||
71 | #define TUPLE_IS_ARRAY (2,(3,4)) | |
72 | #define TUPLE_IS_LIST (anydata,BOOST_PP_NIL) | |
73 | #define TUPLE_IS_LIST_OR_ARRAY (2,(3,BOOST_PP_NIL)) | |
74 | #define TUPLE_BUT_INVALID_ARRAY (&2,(3,4)) | |
75 | #define TUPLE_BUT_INVALID_LIST (anydata,^BOOST_PP_NIL) | |
76 | #define SEQUENCE_EMPTY | |
77 | #define SEQUENCE_MULTI TUPLE_BUT_INVALID_ARRAY TUPLE_BUT_INVALID_LIST | |
78 | ||
79 | BOOST_VMD_GET_TYPE(TUPLE_IS_ARRAY) will return BOOST_VMD_TYPE_ARRAY, the most specific type | |
80 | BOOST_VMD_GET_TYPE(TUPLE_IS_ARRAY,BOOST_VMD_RETURN_TYPE_TUPLE) will return BOOST_VMD_TYPE_TUPLE | |
81 | BOOST_VMD_GET_TYPE(TUPLE_IS_ARRAY,BOOST_VMD_RETURN_TYPE_ARRAY) will return BOOST_VMD_TYPE_ARRAY | |
82 | BOOST_VMD_GET_TYPE(TUPLE_IS_ARRAY,BOOST_VMD_RETURN_TYPE_LIST) will return BOOST_VMD_TYPE_TUPLE | |
83 | ||
84 | BOOST_VMD_GET_TYPE(TUPLE_IS_LIST) will return BOOST_VMD_TYPE_LIST, the most specific type | |
85 | BOOST_VMD_GET_TYPE(TUPLE_IS_LIST,BOOST_VMD_RETURN_TYPE_TUPLE) will return BOOST_VMD_TYPE_TUPLE | |
86 | BOOST_VMD_GET_TYPE(TUPLE_IS_LIST,BOOST_VMD_RETURN_TYPE_ARRAY) will return BOOST_VMD_TYPE_TUPLE | |
87 | BOOST_VMD_GET_TYPE(TUPLE_IS_LIST,BOOST_VMD_RETURN_TYPE_LIST) will return BOOST_VMD_TYPE_LIST | |
88 | ||
89 | BOOST_VMD_GET_TYPE(TUPLE_IS_LIST_OR_ARRAY) will return BOOST_VMD_TYPE_LIST, the most specific type | |
90 | BOOST_VMD_GET_TYPE(TUPLE_IS_LIST_OR_ARRAY,BOOST_VMD_RETURN_TYPE_TUPLE) will return BOOST_VMD_TYPE_TUPLE | |
91 | BOOST_VMD_GET_TYPE(TUPLE_IS_LIST_OR_ARRAY,BOOST_VMD_RETURN_TYPE_ARRAY) will return BOOST_VMD_TYPE_ARRAY | |
92 | BOOST_VMD_GET_TYPE(TUPLE_IS_LIST_OR_ARRAY,BOOST_VMD_RETURN_TYPE_LIST) will return BOOST_VMD_TYPE_LIST | |
93 | ||
94 | BOOST_VMD_GET_TYPE(TUPLE_BUT_INVALID_ARRAY) will give UB | |
95 | BOOST_VMD_GET_TYPE(TUPLE_BUT_INVALID_ARRAY,BOOST_VMD_RETURN_TYPE_TUPLE) will return BOOST_VMD_TYPE_TUPLE | |
96 | BOOST_VMD_GET_TYPE(TUPLE_BUT_INVALID_ARRAY,BOOST_VMD_RETURN_TYPE_ARRAY) will give UB | |
97 | BOOST_VMD_GET_TYPE(TUPLE_BUT_INVALID_ARRAY,BOOST_VMD_RETURN_TYPE_LIST) will return BOOST_VMD_TYPE_TUPLE | |
98 | ||
99 | BOOST_VMD_GET_TYPE(TUPLE_BUT_INVALID_LIST) will give UB | |
100 | BOOST_VMD_GET_TYPE(TUPLE_BUT_INVALID_LIST,BOOST_VMD_RETURN_TYPE_TUPLE) will return BOOST_VMD_TYPE_TUPLE | |
101 | BOOST_VMD_GET_TYPE(TUPLE_BUT_INVALID_LIST,BOOST_VMD_RETURN_TYPE_ARRAY) will return BOOST_VMD_TYPE_TUPLE | |
102 | BOOST_VMD_GET_TYPE(TUPLE_BUT_INVALID_LIST,BOOST_VMD_RETURN_TYPE_LIST) will give UB | |
103 | ||
104 | BOOST_VMD_GET_TYPE(SEQUENCE_EMPTY) | |
105 | will always return BOOST_VMD_TYPE_EMPTY even if we add any return type modifiers | |
106 | BOOST_VMD_GET_TYPE(SEQUENCE_MULTI) | |
107 | will always return BOOST_VMD_TYPE_SEQUENCE even if we add any return type modifiers | |
108 | ||
109 | [heading Usage with sequence converting macros] | |
110 | ||
111 | The sequence converting macros converts a sequence to a composite Boost PP data type | |
112 | or to variadic data, where each element's data in the sequence becomes an element in the | |
113 | destination composite type. The macros are: | |
114 | ||
115 | * BOOST_VMD_TO_ARRAY, converts the sequence to an array | |
116 | * BOOST_VMD_TO_LIST, converts the sequence to a list | |
117 | * BOOST_VMD_TO_SEQ, converts the sequence to a seq | |
118 | * BOOST_VMD_TO_TUPLE, converts the sequence to a tuple | |
119 | * BOOST_VMD_ENUM, converts the sequence to variadic data | |
120 | ||
121 | When it does the conversion, using just the required parameter of the sequence itself, | |
122 | it converts only the data value of each sequence element to the | |
123 | elements of a composite Boost PP data type or variadic data. Because it needs only the data | |
124 | value of each sequence element it determines the type of each sequence element as | |
125 | the most general type that it can be. This means that all tuple-like data are parsed as | |
126 | tuples rather than as possible lists or arrays. | |
127 | ||
128 | Using a return type modifier we can convert from a VMD sequence to a | |
129 | Boost PP composite data type or variadic data and retain the type of data of each | |
130 | element in the sequence as part of the conversion. When doing this each of the | |
131 | converted elements of the composite data type becomes a two-element tuple where | |
132 | the first element is the type of the data and the second element is the data itself. | |
133 | ||
134 | For the sequence conversion macros the default return type modifier internally set is | |
135 | BOOST_VMD_RETURN_NO_TYPE, which means that the type is not retained. | |
136 | By specifying another optional return type modifier | |
137 | we tell the conversion to preserve the type in the conversion output. | |
138 | ||
139 | If the sequence is empty, since there are no sequence elements, | |
140 | any return type modifier we use accomplishes nothing but is fine to use. | |
141 | ||
142 | First we show how sequence conversion macros work with the BOOST_VMD_RETURN_TYPE | |
143 | modifier, which always parses for the most specific type. | |
144 | ||
145 | #include <boost/vmd/enum.hpp> | |
146 | #include <boost/vmd/to_array.hpp> | |
147 | #include <boost/vmd/to_list.hpp> | |
148 | #include <boost/vmd/to_seq.hpp> | |
149 | #include <boost/vmd/to_tuple.hpp> | |
150 | ||
151 | #define BOOST_VMD_REGISTER_ANID (ANID) | |
152 | #define SEQUENCE_EMPTY_1 | |
153 | #define SEQUENCE_SINGLE 35 | |
154 | #define SEQUENCE_SINGLE_ID ANID | |
155 | #define SEQUENCE_SINGLE_ARRAY (3,(0,1,2)) | |
156 | #define SEQUENCE_SINGLE_LIST (data,(more_data,BOOST_PP_NIL)) | |
157 | #define SEQUENCE_MULTI_1 (0,1) (2)(3)(4) | |
158 | #define SEQUENCE_MULTI_2 BOOST_VMD_TYPE_SEQ (2,(5,6)) | |
159 | ||
160 | BOOST_VMD_TO_ARRAY(SEQUENCE_EMPTY_1) will return an empty array '(0,())' | |
161 | BOOST_VMD_TO_ARRAY(SEQUENCE_EMPTY_1,BOOST_VMD_RETURN_TYPE) will return an empty array '(0,())' | |
162 | ||
163 | BOOST_VMD_TO_LIST(SEQUENCE_SINGLE) will return a one-element list '(35,BOOST_PP_NIL)' | |
164 | BOOST_VMD_TO_LIST(SEQUENCE_SINGLE,BOOST_VMD_RETURN_TYPE) | |
165 | will return a one-element list '((BOOST_VMD_TYPE_NUMBER,35),BOOST_PP_NIL)' | |
166 | ||
167 | BOOST_VMD_TO_SEQ(SEQUENCE_SINGLE_ID) will return a one-element seq '(ANID)' | |
168 | BOOST_VMD_TO_SEQ(SEQUENCE_SINGLE_ID,BOOST_VMD_RETURN_TYPE) | |
169 | will return a one-element seq '((BOOST_VMD_TYPE_IDENTIFIER,ANID))' | |
170 | ||
171 | BOOST_VMD_TO_TUPLE(SEQUENCE_SINGLE_ARRAY) will return a single element tuple '((3,(0,1,2)))' | |
172 | BOOST_VMD_TO_TUPLE(SEQUENCE_SINGLE_ARRAY,BOOST_VMD_RETURN_TYPE) | |
173 | will return a single element tuple '((BOOST_VMD_TYPE_ARRAY,(3,(0,1,2))))' | |
174 | ||
175 | BOOST_VMD_ENUM(SEQUENCE_SINGLE_LIST) will return the single-element '(data,(more_data,BOOST_PP_NIL))' | |
176 | BOOST_VMD_ENUM(SEQUENCE_SINGLE_LIST,BOOST_VMD_RETURN_TYPE) | |
177 | will return the single element '(BOOST_VMD_TYPE_LIST,(data,(more_data,BOOST_PP_NIL)))' | |
178 | ||
179 | BOOST_VMD_TO_TUPLE(SEQUENCE_MULTI_1) will return a multi-element tuple '((0,1),(2)(3)(4))' | |
180 | BOOST_VMD_TO_TUPLE(SEQUENCE_MULTI_1,BOOST_VMD_RETURN_TYPE) | |
181 | will return a multi-element tuple '((BOOST_VMD_TYPE_TUPLE,(0,1)),(BOOST_VMD_TYPE_SEQ,(2)(3)(4)))' | |
182 | ||
183 | BOOST_VMD_ENUM(SEQUENCE_MULTI_2) will return multi-element variadic data 'BOOST_VMD_TYPE_SEQ,(2,(5,6))' | |
184 | BOOST_VMD_ENUM(SEQUENCE_MULTI_2,BOOST_VMD_RETURN_TYPE) | |
185 | will return multi-element variadic data '(BOOST_VMD_TYPE_TYPE,BOOST_VMD_TYPE_SEQ),(BOOST_VMD_TYPE_ARRAY,(2,(5,6)))' | |
186 | ||
187 | Lets look at how we might use other return type modifiers when doing conversions | |
188 | to avoid UB if we want the type as part of the conversion but | |
189 | the type might be a valid tuple while being an invalid list or array. | |
190 | ||
191 | #define TUPLE_IS_VALID_ARRAY (2,(3,4)) | |
192 | #define TUPLE_IS_VALID_LIST (anydata,BOOST_PP_NIL) | |
193 | #define TUPLE_BUT_INVALID_ARRAY_2 (&2,(3,4)) | |
194 | #define TUPLE_BUT_INVALID_LIST_2 (anydata,^BOOST_PP_NIL) | |
195 | ||
196 | #define SEQUENCE_MULTI_T1 TUPLE_IS_VALID_ARRAY TUPLE_IS_VALID_LIST | |
197 | #define SEQUENCE_MULTI_T2 TUPLE_BUT_INVALID_ARRAY_2 TUPLE_IS_VALID_LIST | |
198 | #define SEQUENCE_MULTI_T3 TUPLE_IS_VALID_ARRAY TUPLE_BUT_INVALID_LIST_2 | |
199 | #define SEQUENCE_MULTI_T4 TUPLE_BUT_INVALID_ARRAY_2 TUPLE_BUT_INVALID_LIST_2 | |
200 | ||
201 | We present a number of uses of various sequence conversions | |
202 | with each of our four different sequences, and show their results. | |
203 | ||
204 | #include <boost/vmd/to_seq.hpp> | |
205 | ||
206 | BOOST_VMD_TO_SEQ(SEQUENCE_MULTI_T1,BOOST_VMD_RETURN_TYPE) | |
207 | will return the seq '((BOOST_VMD_TYPE_ARRAY,(2,(3,4)))) ((BOOST_VMD_TYPE_LIST,(anydata,BOOST_PP_NIL)))' | |
208 | BOOST_VMD_TO_SEQ(SEQUENCE_MULTI_T1,BOOST_VMD_RETURN_TYPE_ARRAY) | |
209 | will return the seq '((BOOST_VMD_TYPE_ARRAY,(2,(3,4)))) ((BOOST_VMD_TYPE_TUPLE,(anydata,BOOST_PP_NIL)))' | |
210 | BOOST_VMD_TO_SEQ(SEQUENCE_MULTI_T1,BOOST_VMD_RETURN_TYPE_LIST) | |
211 | will return the seq '((BOOST_VMD_TYPE_TUPLE,(2,(3,4)))) ((BOOST_VMD_TYPE_LIST,(anydata,BOOST_PP_NIL)))' | |
212 | BOOST_VMD_TO_SEQ(SEQUENCE_MULTI_T1,BOOST_VMD_RETURN_TYPE_TUPLE) | |
213 | will return the seq '((BOOST_VMD_TYPE_TUPLE,(2,(3,4)))) ((BOOST_VMD_TYPE_TUPLE,(anydata,BOOST_PP_NIL)))' | |
214 | ||
215 | The SEQUENCE_MULTI_T1 is a valid array followed by a valid list. All return type | |
216 | modifiers produce their results without any UBs. | |
217 | ||
218 | #include <boost/vmd/to_tuple.hpp> | |
219 | ||
220 | BOOST_VMD_TO_TUPLE(SEQUENCE_MULTI_T2,BOOST_VMD_RETURN_TYPE) | |
221 | will produce UB when attempting to parse the invalid array as an array | |
222 | BOOST_VMD_TO_TUPLE(SEQUENCE_MULTI_T2,BOOST_VMD_RETURN_TYPE_ARRAY) | |
223 | will produce UB when attempting to parse the invalid array as an array | |
224 | BOOST_VMD_TO_TUPLE(SEQUENCE_MULTI_T2,BOOST_VMD_RETURN_TYPE_LIST) | |
225 | will return the tuple '((BOOST_VMD_TYPE_TUPLE,(&2,(3,4))),(BOOST_VMD_TYPE_LIST,(anydata,BOOST_PP_NIL)))' | |
226 | BOOST_VMD_TO_TUPLE(SEQUENCE_MULTI_T2,BOOST_VMD_RETURN_TYPE_TUPLE) | |
227 | will return the tuple '((BOOST_VMD_TYPE_TUPLE,(&2,(3,4))),(BOOST_VMD_TYPE_TUPLE,(anydata,BOOST_PP_NIL)))' | |
228 | ||
229 | The SEQUENCE_MULTI_T2 is an invalid array, but valid tuple, followed by a valid list. | |
230 | ||
231 | In sequence conversion we will get UB whenever we use a return type | |
232 | modifier that parses the data type of the invalid array as an array. But if we use | |
233 | the return type modifiers BOOST_VMD_RETURN_TYPE_LIST or BOOST_VMD_RETURN_TYPE_TUPLE | |
234 | we are never parsing the invalid array as an array but as a tuple instead and therefore | |
235 | we successfully return the type of the invalid array as a BOOST_VMD_TYPE_TUPLE. | |
236 | ||
237 | #include <boost/vmd/to_array.hpp> | |
238 | ||
239 | BOOST_VMD_TO_ARRAY(SEQUENCE_MULTI_T3,BOOST_VMD_RETURN_TYPE) | |
240 | will produce UB when attempting to parse the invalid list as a list | |
241 | BOOST_VMD_TO_ARRAY(SEQUENCE_MULTI_T3,BOOST_VMD_RETURN_TYPE_LIST) | |
242 | will produce UB when attempting to parse the invalid list as a list | |
243 | BOOST_VMD_TO_ARRAY(SEQUENCE_MULTI_T3,BOOST_VMD_RETURN_TYPE_ARRAY) | |
244 | will return the array '(2,((BOOST_VMD_TYPE_ARRAY,(2,(3,4))),(BOOST_VMD_TYPE_TUPLE,(anydata,^BOOST_PP_NIL))))' | |
245 | BOOST_VMD_TO_ARRAY(SEQUENCE_MULTI_T3,BOOST_VMD_RETURN_TYPE_TUPLE) | |
246 | will return the array '(2,((BOOST_VMD_TYPE_TUPLE,(2,(3,4))),(BOOST_VMD_TYPE_TUPLE,(anydata,^BOOST_PP_NIL))))' | |
247 | ||
248 | The SEQUENCE_MULTI_T3 is a valid array followed by an invalid list, but a valid tuple. | |
249 | ||
250 | In sequence conversion we will get UBs whenever we use a return type | |
251 | modifier that parses the data type of the invalid list as a list. But if we use | |
252 | the return type modifiers BOOST_VMD_RETURN_TYPE_ARRAY or BOOST_VMD_RETURN_TYPE_TUPLE | |
253 | we are never parsing the invalid list as a list but as a tuple instead and therefore | |
254 | we successfully return the type of the invalid list as a BOOST_VMD_TYPE_TUPLE. | |
255 | ||
256 | #include <boost/vmd/to_list.hpp> | |
257 | ||
258 | BOOST_VMD_TO_LIST(SEQUENCE_MULTI_T4,BOOST_VMD_RETURN_TYPE) | |
259 | will produce UB when attempting to parse the invalid array or invalid list | |
260 | BOOST_VMD_TO_LIST(SEQUENCE_MULTI_T4,BOOST_VMD_RETURN_TYPE_ARRAY) | |
261 | will produce UB when attempting to parse the invalid array | |
262 | BOOST_VMD_TO_LIST(SEQUENCE_MULTI_T4,BOOST_VMD_RETURN_TYPE_LIST) | |
263 | will produce UB when attempting to parse the invalid list | |
264 | BOOST_VMD_TO_LIST(SEQUENCE_MULTI_T4,BOOST_VMD_RETURN_TYPE_TUPLE) | |
265 | will return the list '((BOOST_VMD_TYPE_TUPLE,(&2,(3,4))),((BOOST_VMD_TYPE_TUPLE,(anydata,^BOOST_PP_NIL)),BOOST_PP_NIL))' | |
266 | ||
267 | The SEQUENCE_MULTI_T4 is an invalid array, but valid tuple, followed by an invalid list, but valid tuple. | |
268 | ||
269 | In sequence conversion we will get UBs whenever we use a return type | |
270 | modifier that parses the sequence other than looking for only valid tuples. So here we must use | |
271 | the return type modifier BOOST_VMD_RETURN_TYPE_TUPLE for a sequence conversion without | |
272 | generating UBs. | |
273 | ||
274 | [heading Usage with BOOST_VMD_ELEM] | |
275 | ||
276 | The default functionality of BOOST_VMD_ELEM when the required parameters are used | |
277 | is to return the particular element's data. When BOOST_VMD_ELEM does this it parses | |
278 | all elements of the sequence by determining the most general type of data for each | |
279 | element. The parsing algorithm stops when it reaches the element number whose data | |
280 | is returned. This means that all tuple-like data are parsed as tuples rather than | |
281 | as possible lists or arrays. | |
282 | ||
283 | Using return type modifiers as optional parameters we can tell BOOST_VMD_ELEM to | |
284 | return the type of the element found, as well as its data, in the form of a two | |
285 | element tuple. The first element of the tuple is the type of the data and the | |
286 | second element of the tuple is the data itself. | |
287 | ||
288 | When we use a return type modifier with BOOST_VMD_ELEM, which tells us to return | |
289 | the type of the data along with the data, the particular modifier only tells | |
290 | BOOST_VMD_ELEM how to parse the type of data for the element found. | |
291 | BOOST_VMD_ELEM will continue to parse elements in the sequence preceding the | |
292 | element found by determining the most general type of the data since this is | |
293 | the safest way of parsing the data itself. | |
294 | ||
295 | Using the return type modifier BOOST_VMD_RETURN_TYPE with BOOST_VMD_ELEM is | |
296 | perfectly safe as long as the particular element found is not an invalid list | |
297 | or array, but a valid tuple. It is when the element found may be an invalid | |
298 | list or invalid array that we must use other return type modifiers in order | |
299 | to parse the type of the element correctly. | |
300 | ||
301 | #include <boost/vmd/elem.hpp> | |
302 | ||
303 | #define BOOST_VMD_REGISTER_ANID_E (ANID_E) | |
304 | #define SEQUENCE_SINGLE_E 35 | |
305 | #define SEQUENCE_SINGLE_E2 ANID_E | |
306 | #define SEQUENCE_MULTI_E (0,1) (2)(3)(4) | |
307 | #define SEQUENCE_MULTI_E_2 BOOST_VMD_TYPE_SEQ (2,(5,6)) | |
308 | ||
309 | BOOST_VMD_ELEM(0,SEQUENCE_SINGLE_E) will return '35' | |
310 | BOOST_VMD_ELEM(0,SEQUENCE_SINGLE_E,BOOST_VMD_RETURN_TYPE) will return '(BOOST_VMD_TYPE_NUMBER,35)' | |
311 | ||
312 | BOOST_VMD_ELEM(0,SEQUENCE_SINGLE_E2) will return 'ANID_E' | |
313 | BOOST_VMD_ELEM(0,SEQUENCE_SINGLE_E2,BOOST_VMD_RETURN_TYPE) will return '(BOOST_VMD_TYPE_IDENTIFIER,ANID_E)' | |
314 | ||
315 | BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E) will return '(2)(3)(4)' | |
316 | BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E,BOOST_VMD_RETURN_TYPE) will return '(BOOST_VMD_TYPE_SEQ,(2)(3)(4))' | |
317 | ||
318 | BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E_2) will return 'BOOST_VMD_TYPE_SEQ' | |
319 | BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E_2,BOOST_VMD_RETURN_TYPE) will return '(BOOST_VMD_TYPE_TYPE,BOOST_VMD_TYPE_SEQ)' | |
320 | ||
321 | When we use the other return type modifiers with BOOST_VMD_ELEM we do so | |
322 | because the element we want may be an invalid list or an invalid array | |
323 | but a valid tuple and yet we still want its type returned as part of the result. | |
324 | ||
325 | Let's look at how this works with BOOST_VMD_ELEM by specifying VMD sequences | |
326 | that have tuples which are in the form of arrays or lists which cannot be | |
327 | parsed as such by VMD without generating UBs. | |
328 | ||
329 | #define TUPLE_IS_VALID_ARRAY_E (2,(3,4)) | |
330 | #define TUPLE_IS_VALID_LIST_E (anydata,BOOST_PP_NIL) | |
331 | #define TUPLE_BUT_INVALID_ARRAY_E (&2,(3,4)) | |
332 | #define TUPLE_BUT_INVALID_LIST_E (anydata,^BOOST_PP_NIL) | |
333 | ||
334 | #define SEQUENCE_MULTI_E1 TUPLE_IS_VALID_ARRAY_E TUPLE_IS_VALID_LIST_E | |
335 | #define SEQUENCE_MULTI_E2 TUPLE_BUT_INVALID_ARRAY_E TUPLE_IS_VALID_LIST_E | |
336 | #define SEQUENCE_MULTI_E3 TUPLE_IS_VALID_ARRAY_E TUPLE_BUT_INVALID_LIST_E | |
337 | #define SEQUENCE_MULTI_E4 TUPLE_BUT_INVALID_ARRAY_E TUPLE_BUT_INVALID_LIST_E | |
338 | ||
339 | We present a number of uses of BOOST_VMD_ELEM with each of our four | |
340 | different sequences, and show their results. | |
341 | ||
342 | #include <boost/vmd/elem.hpp> | |
343 | ||
344 | BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E1,BOOST_VMD_RETURN_TYPE) will return '(BOOST_VMD_TYPE_ARRAY,(2,(3,4)))' | |
345 | BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E1,BOOST_VMD_RETURN_TYPE_ARRAY) will return '(BOOST_VMD_TYPE_ARRAY,(2,(3,4)))' | |
346 | BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E1,BOOST_VMD_RETURN_TYPE_LIST) will return '(BOOST_VMD_TYPE_TUPLE,(2,(3,4)))' | |
347 | BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E1,BOOST_VMD_RETURN_TYPE_TUPLE) will return '(BOOST_VMD_TYPE_TUPLE,(2,(3,4)))' | |
348 | BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E1,BOOST_VMD_RETURN_TYPE) will return '(BOOST_VMD_TYPE_LIST,(anydata,BOOST_PP_NIL))' | |
349 | BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E1,BOOST_VMD_RETURN_TYPE_ARRAY) will return '(BOOST_VMD_TYPE_TUPLE,(anydata,BOOST_PP_NIL))' | |
350 | BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E1,BOOST_VMD_RETURN_TYPE_LIST) will return '(BOOST_VMD_TYPE_LIST,(anydata,BOOST_PP_NIL))' | |
351 | BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E1,BOOST_VMD_RETURN_TYPE_TUPLE) will return '(BOOST_VMD_TYPE_TUPLE,(anydata,BOOST_PP_NIL))' | |
352 | ||
353 | The SEQUENCE_MULTI_E1 is a valid array followed by a valid list. All return type | |
354 | modifiers produce their results without any UBs. | |
355 | ||
356 | #include <boost/vmd/elem.hpp> | |
357 | ||
358 | BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E2,BOOST_VMD_RETURN_TYPE) | |
359 | will produce UB when attempting to parse the invalid array as an array | |
360 | BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E2,BOOST_VMD_RETURN_TYPE_ARRAY) | |
361 | will produce UB when attempting to parse the invalid array as an array | |
362 | BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E2,BOOST_VMD_RETURN_TYPE_LIST) will return '(BOOST_VMD_TYPE_TUPLE,(&2,(3,4)))' | |
363 | BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E2,BOOST_VMD_RETURN_TYPE_TUPLE) will return '(BOOST_VMD_TYPE_TUPLE,(&2,(3,4)))' | |
364 | BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E2,BOOST_VMD_RETURN_TYPE) will return '(BOOST_VMD_TYPE_LIST,(anydata,BOOST_PP_NIL))' | |
365 | BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E2,BOOST_VMD_RETURN_TYPE_ARRAY) will return '(BOOST_VMD_TYPE_TUPLE,(anydata,BOOST_PP_NIL))' | |
366 | BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E2,BOOST_VMD_RETURN_TYPE_LIST) will return '(BOOST_VMD_TYPE_LIST,(anydata,BOOST_PP_NIL))' | |
367 | BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E2,BOOST_VMD_RETURN_TYPE_TUPLE) will return '(BOOST_VMD_TYPE_TUPLE,(anydata,BOOST_PP_NIL))' | |
368 | ||
369 | The SEQUENCE_MULTI_E2 is an invalid array, but valid tuple, followed by a valid list. | |
370 | ||
371 | When we access element 0 of our sequence, and use a return type modifier that parses | |
372 | its data type as an array we will get UB. But if we use the return | |
373 | type modifiers BOOST_VMD_RETURN_TYPE_LIST or BOOST_VMD_RETURN_TYPE_TUPLE | |
374 | we are never parsing the invalid array as an array but as a tuple instead and therefore | |
375 | we successfully return the type of the invalid array as a BOOST_VMD_TYPE_TUPLE. | |
376 | ||
377 | When we access element 1 of our sequence, which is both a valid list and a valid tuple, | |
378 | we will never get UB. We will get the return type of the element based | |
379 | on which return type modifier we use. | |
380 | ||
381 | #include <boost/vmd/elem.hpp> | |
382 | ||
383 | BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E3,BOOST_VMD_RETURN_TYPE) will return '(BOOST_VMD_TYPE_ARRAY,(2,(3,4)))' | |
384 | BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E3,BOOST_VMD_RETURN_TYPE_ARRAY) will return '(BOOST_VMD_TYPE_ARRAY,(2,(3,4)))' | |
385 | BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E3,BOOST_VMD_RETURN_TYPE_LIST) will return '(BOOST_VMD_TYPE_TUPLE,(2,(3,4)))' | |
386 | BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E3,BOOST_VMD_RETURN_TYPE_TUPLE) will return '(BOOST_VMD_TYPE_TUPLE,(2,(3,4)))' | |
387 | BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E3,BOOST_VMD_RETURN_TYPE) | |
388 | will produce UB when attempting to parse the invalid list as a list | |
389 | BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E3,BOOST_VMD_RETURN_TYPE_ARRAY) will return '(BOOST_VMD_TYPE_TUPLE,(anydata,BOOST_PP_NIL))' | |
390 | BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E3,BOOST_VMD_RETURN_TYPE_LIST) | |
391 | will produce UB when attempting to parse the invalid list as a list | |
392 | BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E3,BOOST_VMD_RETURN_TYPE_TUPLE) will return '(BOOST_VMD_TYPE_TUPLE,(anydata,BOOST_PP_NIL))' | |
393 | ||
394 | The SEQUENCE_MULTI_E3 is a valid array followed by an invalid list, but valid tuple. | |
395 | ||
396 | When we access element 0 of our sequence, which is both a valid array and a valid tuple, | |
397 | we will never get UB. We will get the return type of the element based | |
398 | on which return type modifier we use. | |
399 | ||
400 | When we access element 1 of our sequence, and use a return type modifier that parses | |
401 | its data type as a list we will get UB. But if we use the return | |
402 | type modifiers BOOST_VMD_RETURN_TYPE_ARRAY or BOOST_VMD_RETURN_TYPE_TUPLE | |
403 | we are never parsing the invalid list as a list but as a tuple instead and therefore | |
404 | we successfully return the type of the invalid list as a BOOST_VMD_TYPE_TUPLE. | |
405 | ||
406 | #include <boost/vmd/elem.hpp> | |
407 | ||
408 | BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E4,BOOST_VMD_RETURN_TYPE) | |
409 | will produce UB when attempting to parse the invalid array | |
410 | BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E4,BOOST_VMD_RETURN_TYPE_ARRAY) | |
411 | will produce UB when attempting to parse the invalid array | |
412 | BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E4,BOOST_VMD_RETURN_TYPE_LIST) will return '(BOOST_VMD_TYPE_TUPLE,(2,(3,4)))' | |
413 | BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E4,BOOST_VMD_RETURN_TYPE_TUPLE) will return '(BOOST_VMD_TYPE_TUPLE,(2,(3,4)))' | |
414 | BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E4,BOOST_VMD_RETURN_TYPE) | |
415 | will produce UB when attempting to parse the invalid list | |
416 | BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E4,BOOST_VMD_RETURN_TYPE_ARRAY) will return '(BOOST_VMD_TYPE_TUPLE,(anydata,BOOST_PP_NIL))' | |
417 | BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E4,BOOST_VMD_RETURN_TYPE_LIST) | |
418 | will produce UB when attempting to parse the invalid list | |
419 | BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E4,BOOST_VMD_RETURN_TYPE_TUPLE) will return '(BOOST_VMD_TYPE_TUPLE,(anydata,BOOST_PP_NIL))' | |
420 | ||
421 | The SEQUENCE_MULTI_E4 is an invalid array, but valid tuple, followed by an invalid list, but valid tuple. | |
422 | ||
423 | When we access element 0 of our sequence, which is an invalid array but a valid tuple, | |
424 | we must use a return type modifier which does not parse element 0 as an array, else | |
425 | we will get UB. This means we must use the return | |
426 | type modifiers BOOST_VMD_RETURN_TYPE_LIST or BOOST_VMD_RETURN_TYPE_TUPLE so | |
427 | we are never parsing the invalid array as an array but as a tuple instead and therefore | |
428 | we successfully return the type of the invalid array as a BOOST_VMD_TYPE_TUPLE. | |
429 | ||
430 | When we access element 1 of our sequence, which is an invalid list but a valid tuple, | |
431 | we must use a return type modifier which does not parse element 1 as a list, else | |
432 | we will get UB. This means we must use the return | |
433 | type modifiers BOOST_VMD_RETURN_TYPE_ARRAY or BOOST_VMD_RETURN_TYPE_TUPLE so | |
434 | we are never parsing the invalid list as a list but as a tuple instead and therefore | |
435 | we successfully return the type of the invalid list as a BOOST_VMD_TYPE_TUPLE. | |
436 | ||
437 | [heading Usage with other modifiers of BOOST_VMD_ELEM] | |
438 | ||
439 | We have not yet discussed the rest of the modifiers which may be | |
440 | used with BOOST_VMD_ELEM, but return type modifiers are completely | |
441 | independent of any of them. This means they can be combined with | |
442 | other modifiers and whenever the element of the sequence is | |
443 | returned the return type modifiers determine of what the value of that | |
444 | element consists; whether it be just the element data or the element | |
445 | as a type/data tuple with the type parsed according to our return type | |
446 | modifier. When we subsequently discuss the use of other modifiers with | |
447 | BOOST_VMD_ELEM and refer to the element being returned, we are referring | |
448 | to that element as it is determined by the return type modifiers, which | |
449 | by default only returns the element's data. | |
450 | ||
451 | [endsect] |