vmd_equality.qbk 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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_assert Testing for equality and inequality]
  8. VMD allows the programmer to test generically for the equality or inequality
  9. of any value which VMD can parse. This includes emptiness, identifiers, numbers,
  10. types, arrays, lists, seqs, tuples, and multi-element sequences.
  11. The macro to test for equality is called BOOST_VMD_EQUAL and it has two required
  12. parameters which are the two values against which to test. The values can be any
  13. VMD data type.
  14. For the composite data types of array, list, seq, and tuple, or any of those types
  15. in a multi-element sequence, the elements of those types must also be a data type
  16. which VMD can parse. BOOST_VMD_EQUAL recursively parses the elements in a composite data type
  17. for equality, up to a level of 16 inner types, to test that one composite type
  18. equals another composite type. The requirement, that composite elements must also
  19. be a data type which VMD can parse, is different from most other macros
  20. in the VMD library, where only the top-level composite type need be parsed enough to
  21. determine the type of the data. If BOOST_VMD_EQUAL encounters a data type which it
  22. cannot parse the result will be UB.
  23. VMD identifiers used in equality testing must be registered and pre-detected.
  24. All numbers and v-types are already registered/pre-detected for equality testing
  25. so it is only user-defined identifiers which must be registered and pre-detected.
  26. If an identifier has not been both registered and predetected it will never be
  27. equal to the same identifier value, so it will always fail equality testing,
  28. although it will not give a preprocessing error doing so.
  29. The BOOST_VMD_EQUAL macro returns 1 if both parameters are equal and 0 if the
  30. parameters are not equal.
  31. Conversely to test for inequality, of the same values as are required in testing
  32. for equality, the VMD library has the macro BOOST_VMD_NOT_EQUAL. This macro is simply
  33. a complement of the BOOST_VMD_EQUAL macro. If BOOST_VMD_EQUAL returns 1 then
  34. BOOST_VMD_NOT_EQUAL returns 0 and if BOOST_VMD_EQUAL returns 0 then
  35. BOOST_VMD_NOT_EQUAL returns 1.
  36. The BOOST_VMD_EQUAL and BOOST_VMD_NOT_EQUAL macros are called "equality macros".
  37. #include <boost/vmd/equal.hpp>
  38. #define BOOST_VMD_REGISTER_AN_ID1 (AN_ID1)
  39. #define BOOST_VMD_REGISTER_AN_ID2 (AN_ID2)
  40. #define BOOST_VMD_DETECT_AN_ID1_AN_ID1
  41. #define BOOST_VMD_DETECT_AN_ID2_AN_ID2
  42. #define AN_IDENTIFIER1 AN_ID1
  43. #define AN_IDENTIFIER2 AN_ID2
  44. #define AN_IDENTIFIER3 AN_ID1 // same as AN_IDENTIFIER1 = AN_ID1
  45. #define A_NUMBER1 33
  46. #define A_NUMBER2 145
  47. #define A_NUMBER3 33 // same as A_NUMBER1 = 33
  48. #define A_TUPLE1 (AN_IDENTIFIER1,A_NUMBER1)
  49. #define A_TUPLE2 (AN_IDENTIFIER1,A_NUMBER2)
  50. #define A_TUPLE3 (AN_IDENTIFIER3,A_NUMBER3) // same as A_TUPLE1 = (AN_ID1,33)
  51. #define A_SEQ1 (A_NUMBER1)(A_TUPLE1)
  52. #define A_SEQ2 (A_NUMBER2)(A_TUPLE2)
  53. #define A_SEQ3 (A_NUMBER3)(A_TUPLE3) // same as A_SEQ1 = (33)((AN_ID1,33))
  54. BOOST_VMD_EQUAL(AN_IDENTIFIER1,AN_IDENTIFIER2) will return 0
  55. BOOST_VMD_EQUAL(AN_IDENTIFIER1,AN_IDENTIFIER3) will return 1
  56. BOOST_VMD_EQUAL(A_NUMBER1,A_NUMBER2) will return 0
  57. BOOST_VMD_EQUAL(A_NUMBER1,A_NUMBER3) will return 1
  58. BOOST_VMD_EQUAL(A_TUPLE1,A_TUPLE2) will return 0
  59. BOOST_VMD_EQUAL(A_TUPLE1,A_TUPLE3) will return 1
  60. BOOST_VMD_EQUAL(A_SEQ1,A_SEQ2) will return 0
  61. BOOST_VMD_EQUAL(A_SEQ1,A_SEQ3) will return 1
  62. When BOOST_VMD_EQUAL tests for equality it always parses data for their most
  63. specific types. The reason for this is that a valid tuple, which is also an invalid
  64. list or array, can never be compared completely because all elements of that tuple
  65. are not data types which VMD can parse. Therefore VMD always tests equality based
  66. on the most specific type for any value being tested, which speeds up testing for
  67. the more specific tuple data types such as lists and arrays.
  68. #define TUPLE_IS_ARRAY1 (2,(3,4))
  69. #define TUPLE_IS_ARRAY2 (2,(4,5))
  70. #define TUPLE_IS_ARRAY3 (2,(3,4))
  71. #define TUPLE_IS_LIST1 (55,BOOST_PP_NIL)
  72. #define TUPLE_IS_LIST2 (135,BOOST_PP_NIL)
  73. #define TUPLE_IS_LIST3 (55,BOOST_PP_NIL)
  74. #define TUPLE_IS_LIST_OR_ARRAY1 (2,(3,BOOST_PP_NIL))
  75. #define TUPLE_IS_LIST_OR_ARRAY2 (2,(4,BOOST_PP_NIL))
  76. #define TUPLE_IS_LIST_OR_ARRAY3 (2,(3,BOOST_PP_NIL))
  77. #define TUPLE_BUT_INVALID_ARRAY1 (&2,(3,4))
  78. #define TUPLE_BUT_INVALID_ARRAY2 (&2,(4,4))
  79. #define TUPLE_BUT_INVALID_ARRAY3 (&2,(3,4))
  80. #define TUPLE_BUT_INVALID_LIST1 (55,^BOOST_PP_NIL)
  81. #define TUPLE_BUT_INVALID_LIST2 (135,^BOOST_PP_NIL)
  82. #define TUPLE_BUT_INVALID_LIST3 (55,^BOOST_PP_NIL)
  83. All of the constructs above are valid tuples.
  84. The first three are valid arrays, so they will be parsed and compared
  85. as arrays, so that they can be used as in:
  86. #include <boost/vmd/equal.hpp>
  87. BOOST_VMD_EQUAL(TUPLE_IS_ARRAY1,TUPLE_IS_ARRAY2) will return 0
  88. BOOST_VMD_EQUAL(TUPLE_IS_ARRAY1,TUPLE_IS_ARRAY3) will return 1
  89. The next three are valid lists, so they will be parsed and compared
  90. as lists, so that they can be used as in:
  91. #include <boost/vmd/equal.hpp>
  92. BOOST_VMD_EQUAL(TUPLE_IS_LIST1,TUPLE_IS_LIST2) will return 0
  93. BOOST_VMD_EQUAL(TUPLE_IS_LIST1,TUPLE_IS_LIST3) will return 1
  94. The next three are valid lists or arrays but will be parsed as lists
  95. because lists are more specific than arrays. They can be used as in:
  96. #include <boost/vmd/equal.hpp>
  97. BOOST_VMD_EQUAL(TUPLE_IS_LIST_OR_ARRAY1,TUPLE_IS_LIST_OR_ARRAY2) will return 0
  98. BOOST_VMD_EQUAL(TUPLE_IS_LIST_OR_ARRAY1,TUPLE_IS_LIST_OR_ARRAY3) will return 1
  99. The next three are valid tuples but invalid arrays. The BOOST_VMD_EQUAL
  100. macro attempts to parse them as the most specific type they can be, which is an
  101. array. But the attempt to parse them as arrays will lead to UB
  102. because the number which signifies the size of the array is invalid as
  103. a number. Now let us suppose we should parse them as the less specific type
  104. of a tuple instead of as an array. This will still give UB
  105. if we will attempt to compare the first tuple element against a corresponding
  106. first tuple element of another tuple, and when we do will again encounter UB
  107. because it is not a data type VMD can parse.
  108. #include <boost/vmd/equal.hpp>
  109. BOOST_VMD_EQUAL(TUPLE_BUT_INVALID_ARRAY1,TUPLE_BUT_INVALID_ARRAY1) will generate UB
  110. BOOST_VMD_EQUAL(TUPLE_BUT_INVALID_ARRAY1,TUPLE_BUT_INVALID_ARRAY1) will generate UB
  111. The next three are valid tuples but invalid lists. The BOOST_VMD_EQUAL
  112. macro attempts to parse them as the most specific type they can be, which is
  113. a list. But the attempt to parse them as lists will lead to UB
  114. because the identifier which signifies the end-of-list is invalid as
  115. an identifier. Now let us suppose we should parse them as the less specific type
  116. of a tuple instead of as a list. This will still give UB
  117. if we will attempt to compare the second tuple element against a corresponding
  118. second tuple element of another tuple, and when we do will again encounter UB
  119. because it is not a data type VMD can parse.
  120. #include <boost/vmd/equal.hpp>
  121. BOOST_VMD_EQUAL(TUPLE_BUT_INVALID_LIST1,TUPLE_BUT_INVALID_LIST2) will generate UB
  122. BOOST_VMD_EQUAL(TUPLE_BUT_INVALID_LIST1,TUPLE_BUT_INVALID_LIST3) will generate UB
  123. It is possible that a composite data type which has an element which VMD cannot parse
  124. will not give UB when compared for equality, but rather just the test for equality
  125. will fail. This can occur if the algorithm which tests for equality tests false before parsing of
  126. the particular element. Such a situation might be:
  127. #include <boost/vmd/equal.hpp>
  128. #define A_TUPLE1 (3,4,"astring")
  129. #define A_TUPLE2 (3,4)
  130. BOOST_VMD_EQUAL(A_TUPLE1,A_TUPLE2) will return 0 rather than generate UB
  131. The reason the above correctly returns 0, rather than generate UB when
  132. VMD attempts to parse '"astring"', which is not a data type VMD can parse, is because the
  133. algorithm for testing equality tests whether or not the tuples have the same number of elements
  134. before it tests for the equality of each element. This is just one example where testing for
  135. equality may fail before UB is generated when BOOST_VMD_EQUAL attempts to
  136. parse a data type which it cannot handle. Nevertheless the general rule should still be considered
  137. that for BOOST_VMD_EQUAL/BOOT_VMD_NOT_EQUAL all data types, even an element of a composite data
  138. type, must be a VMD data type if the macro is to work properly, else UB could occur.
  139. [heading Usage]
  140. You can use the general header file:
  141. #include <boost/vmd/vmd.hpp>
  142. or you can use the individual header files:
  143. #include <boost/vmd/equal.hpp> for the BOOST_VMD_EQUAL macro
  144. #include <boost/vmd/not_equal.hpp> for the BOOST_VMD_NOT_EQUAL macro
  145. [endsect]