vmd_modifiers_return_type.qbk 25 KB

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