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