vmd_pp_data_types.qbk 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  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_pp_data_types VMD and Boost PP data types]
  8. VMD is able to determine whether or not preprocessing input
  9. is a given Boost PP data type. The VMD macros to do this are:
  10. * BOOST_VMD_IS_ARRAY for an array
  11. * BOOST_VMD_IS_LIST for a list
  12. * BOOST_VMD_IS_SEQ for a seq
  13. * BOOST_VMD_IS_TUPLE for a tuple
  14. Each of these macros take a single parameter as input and
  15. return 1 if the parameter is the appropriate data type and
  16. 0 if it is not.
  17. [heading Syntax anomalies]
  18. Both an array and a non-empty list are also a tuple. So if
  19. one has:
  20. #define ANARRAY (3,(a,b,c))
  21. #define ALIST (a,(b,(c,BOOST_PP_NIL)))
  22. #define ATUPLE (a,b,c)
  23. #define ASEQ (a)(b)(c)
  24. then
  25. #include <boost/vmd/is_tuple.hpp>
  26. BOOST_VMD_IS_TUPLE(ANARRAY) returns 1
  27. BOOST_VMD_IS_TUPLE(ALIST) returns 1
  28. BOOST_VMD_IS_TUPLE(ATUPLE) returns 1
  29. BOOST_VMD_IS_TUPLE(ASEQ) returns 0
  30. A list whose first element is the number 2 and whose second
  31. element is not the end-of-list marker BOOST_PP_NIL is also
  32. an array. So if one has:
  33. #define ALIST (2,(3,BOOST_PP_NIL))
  34. #define ALIST2 (2,(3,(4,BOOST_PP_NIL)))
  35. #define ALIST3 (2,BOOST_PP_NIL)
  36. #include <boost/vmd/is_array.hpp>
  37. #include <boost/vmd/is_list.hpp>
  38. BOOST_VMD_IS_LIST(ALIST) returns 1
  39. BOOST_VMD_IS_LIST(ALIST2) returns 1
  40. BOOST_VMD_IS_LIST(ALIST3) returns 1
  41. BOOST_VMD_IS_ARRAY(ALIST) returns 1
  42. BOOST_VMD_IS_ARRAY(ALIST2) returns 1
  43. BOOST_VMD_IS_ARRAY(ALIST3) returns 0
  44. A single element tuple is also a one element seq. So if one has:
  45. #define ASE_TUPLE (a)
  46. then
  47. #include <boost/vmd/is_seq.hpp>
  48. #include <boost/vmd/is_tuple.hpp>
  49. BOOST_VMD_IS_TUPLE(ASE_TUPLE) returns 1
  50. BOOST_VMD_IS_SEQ(ASE_TUPLE) returns 1
  51. [heading Problem when testing an array]
  52. The form of an array is a two element tuple, where the first
  53. element is a number and the second element is a tuple. The number
  54. specifies the size of the tuple. Since when using variadic macros
  55. it is never necessary to specify the size of a tuple, an array is
  56. largely obsolete. However VMD still supports it.
  57. The problem when testing for an array is that if the first element
  58. does not obey the constraint on testing for a number, you will get
  59. UB.
  60. #include <boost/vmd/is_array.hpp>
  61. #include <boost/vmd/is_tuple.hpp>
  62. #define A_TUPLE (&anything,(1,2))
  63. BOOST_VMD_IS_ARRAY(A_TUPLE) will give UB due to the constraint
  64. BOOST_VMD_IS_TUPLE(A_TUPLE) will return 1
  65. When VMD attempts to parse for an array, as it does when the BOOST_VMD_IS_ARRAY
  66. is used, if first looks to see if the syntax represents a tuple with two elements.
  67. Next it looks to see if the second element itself is a tuple. Finally if it is
  68. satisfied that the previous checks are valid it tests whether the first element
  69. is a number or not. It is in this final test, that the first element is a valid
  70. number, where the UB could occur as explained in the topic 'Numbers'.
  71. [heading Problem when testing a list]
  72. The form of a non-empty list is a two element tuple, where the first
  73. element is the head of the list and can be anything and the
  74. second element is itself a list or the end-of-list identifier
  75. BOOST_PP_NIL.
  76. The problem when testing for a list is that if the second element
  77. does not obey the constraint on testing for an identifier, since BOOST_PP_NIL
  78. is an identifier and is tested as such, you will get UB.
  79. #include <boost/vmd/is_list.hpp>
  80. #include <boost/vmd/is_tuple.hpp>
  81. #define A_TUPLE (element,&anything)
  82. BOOST_VMD_IS_LIST(A_TUPLE) will give UB due to the constraint
  83. BOOST_VMD_IS_TUPLE(A_TUPLE) will return 1
  84. The form of an empty list is the identifier BOOST_PP_NIL. Therefore:
  85. #include <boost/vmd/is_identifier.hpp>
  86. #include <boost/vmd/is_list.hpp>
  87. #define A_BAD_EMPTY_LIST &BOOST_PP_NIL
  88. BOOST_VMD_IS_LIST(A_BAD_EMPTY_LIST) will give UB due to the constraint
  89. BOOST_VMD_IS_IDENTIFIER(A_BAD_EMPTY_LIST) will give UB due to the constraint
  90. When VMD attempts to parse for a list, as it does when the BOOST_VMD_IS_LIST
  91. is used, if first looks to see if the syntax represents a tuple with two elements.
  92. If it is not a tuple with two elements it will check for the end-of-list.
  93. If it is a tuple with two elements it looks to see if the second element is a list.
  94. In both these paths it must always eventually check for the end-of-list notation
  95. BOOST_PP_NIL, which is an identifier in VMD. It is in this final test, that the
  96. end-of-list notation exists as a VMD identifier, where the UB
  97. could occur as explained in the topic 'Identifiers'.
  98. [heading Distinguishing a seq and a tuple]
  99. As has previously been mentioned a single element tuple
  100. is also a one element seq.
  101. However, as will be discussed later in the documentation, when VMD has to
  102. determine the type of such data, it always returns it as a tuple ( BOOST_VMD_TYPE_TUPLE ).
  103. If our data consists of more than one consecutive tuple of a single
  104. element the data is a seq:
  105. #include <boost/vmd/is_seq.hpp>
  106. #include <boost/vmd/is_tuple.hpp>
  107. #define ST_DATA (somedata)(some_other_data)
  108. BOOST_VMD_IS_SEQ(ST_DATA) will return 1
  109. BOOST_VMD_IS_TUPLE(ST_DATA) will return 0
  110. However if the data consists of a mixture we need to distinguish
  111. how VMD parses the data. The rule is that VMD always parses a single
  112. element tuple as a tuple unless it is followed by one or more single
  113. element tuples, in which case it is a seq.
  114. #define ST_DATA (somedata)(element1,element2)
  115. VMD parses the above data as 2 consecutive tuples.
  116. The first tuple is the single element tuple '(somedata)' and the second tuple
  117. is the multi element tuple '(element1,element2)'.
  118. #define ST_DATA (element1,element2)(somedata)
  119. VMD parses the above data as 2 consecutive tuples.
  120. The first tuple is the multi element tuple '(element1,element2)' and the second tuple
  121. is the single element tuple '(somedata)'.
  122. #define ST_DATA (somedata)(some_other_data)(element1,element2)
  123. VMD parses the above data as a seq followed by a tuple.
  124. The seq is '(somedata)(some_other_data)' and the tuple is
  125. '(element1,element2)'.
  126. [heading Empty Boost PP data types]
  127. An array and a list can be empty.
  128. An empty array has the form '(0,())', and is a perfectly valid array.
  129. You can test for an empty array using the macro BOOST_VMD_IS_EMPTY_ARRAY.
  130. #include <boost/vmd/is_array.hpp>
  131. #include <boost/vmd/is_empty_array.hpp>
  132. #define AN_ARRAY (1,(1))
  133. #define AN_EMPTY_ARRAY (0,())
  134. BOOST_VMD_IS_ARRAY(AN_ARRAY) will return 1
  135. BOOST_VMD_IS_ARRAY(AN_EMPTY_ARRAY) will return 1
  136. BOOST_VMD_IS_EMPTY_ARRAY(AN_EMPTY_ARRAY) will return 1
  137. BOOST_VMD_IS_EMPTY_ARRAY() will return 0
  138. BOOST_VMD_IS_EMPTY_ARRAY(AN_ARRAY) will return 0
  139. An empty list has the form 'BOOST_PP_NIL', and is a perfectly valid list.
  140. You can test for an empty list using the macro BOOST_VMD_IS_EMPTY_LIST.
  141. #include <boost/vmd/is_empty_list.hpp>
  142. #include <boost/vmd/is_list.hpp>
  143. #define A_LIST (1,BOOST_PP_NIL)
  144. #define AN_EMPTY_LIST BOOST_PP_NIL
  145. BOOST_VMD_IS_LIST(A_LIST) will return 1
  146. BOOST_VMD_IS_LIST(AN_EMPTY_LIST) will return 1
  147. BOOST_VMD_IS_EMPTY_LIST(AN_EMPTY_LIST) will return 1
  148. BOOST_VMD_IS_EMPTY_LIST() will return 0
  149. BOOST_VMD_IS_EMPTY_LIST(A_LIST) will return 0
  150. Neither seqs or tuples can be empty when using Boost PP. Because of this if you
  151. convert from an empty array or list to a seq or tuple using
  152. Boost PP macros to do so you will get undefined behavior.
  153. The syntax '()', which is called an empty parenthesis, is neither a
  154. zero-element seq or a tuple consisting of no elements. Rather it is
  155. either a one-element seq whose content is emptiness or a single-element
  156. tuple whose content is emptiness.
  157. VMD supports the syntax of an empty parenthesis. You can test for it using
  158. the macro BOOST_VMD_IS_PARENS_EMPTY.
  159. #include <boost/vmd/is_parens_empty.hpp>
  160. #include <boost/vmd/is_seq.hpp>
  161. #include <boost/vmd/is_tuple.hpp>
  162. #define EMPTY_PARENS ()
  163. #define TUPLE (0)
  164. #define SEQ (0)(1)
  165. BOOST_VMD_IS_TUPLE(EMPTY_PARENS) will return 1
  166. BOOST_VMD_IS_SEQ(EMPTY_PARENS) will return 1
  167. BOOST_VMD_IS_PARENS_EMPTY(EMPTY_PARENS) will return 1
  168. BOOST_VMD_IS_PARENS_EMPTY() will return 0
  169. BOOST_VMD_IS_PARENS_EMPTY(TUPLE) will return 0
  170. BOOST_VMD_IS_PARENS_EMPTY(SEQ) will return 0
  171. The VC++8 compiler ( Visual Studio 2005 ), which is the oldest
  172. VC++ version which VMD supports, has trouble working with the empty
  173. parenthesis syntax. Therefore if you have to use VC++8 avoid its use,
  174. otherwise you should be fine using it if you desire.
  175. [heading Using a tuple instead of an array]
  176. When using variadic macros, the fact that an array can be empty is its only
  177. advantage over a tuple. Otherwise using a tuple is always easier since
  178. the syntax is simpler; you never have to notate the tuple's size.
  179. Since VMD fully supports passing and returning emptiness you could use a tuple
  180. instead of an array in all situations and simply pass or return emptiness to
  181. represent an "empty" tuple, and as an equivalent to an empty array.
  182. This notion of using emptiness to represent an "empty" tuple can also be extended
  183. to using emptiness to represent an "empty" seq. However functionality in Boost PP
  184. will not recognize emptiness as an empty tuple or seq, nor can you work with emptiness
  185. to represent an empty tuple or empty seq using the Boost PP functionality for a tuple
  186. or a seq. For a solution to using emptiness to represent an "empty" tuple or an
  187. "empty" seq VMD has functionality which will be explained when we look at our last
  188. area of functionality in VMD, useful variadic macros not in Boost PP.
  189. [heading Usage]
  190. You can use the general header file:
  191. #include <boost/vmd/vmd.hpp>
  192. or you can use individual header files for each of these macros.
  193. The individual header files are:
  194. #include <boost/vmd/is_array.hpp> // for the BOOST_VMD_IS_ARRAY macro
  195. #include <boost/vmd/is_list.hpp> // for the BOOST_VMD_IS_LIST macro
  196. #include <boost/vmd/is_seq.hpp> // for the BOOST_VMD_IS_SEQ macro
  197. #include <boost/vmd/is_tuple.hpp> // for the BOOST_VMD_IS_TUPLE macro.
  198. #include <boost/vmd/is_empty_array.hpp> // for the BOOST_VMD_IS_EMPTY_ARRAY macro.
  199. #include <boost/vmd/is_empty_list.hpp> // for the BOOST_VMD_IS_EMPTY_LIST macro.
  200. #include <boost/vmd/is_parens_empty.hpp> // for the BOOST_VMD_IS_PARENS_EMPTY macro.
  201. [endsect]