]>
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_assert Testing for equality and inequality] | |
9 | ||
10 | VMD allows the programmer to test generically for the equality or inequality | |
11 | of any value which VMD can parse. This includes emptiness, identifiers, numbers, | |
12 | types, arrays, lists, seqs, tuples, and multi-element sequences. | |
13 | ||
14 | The macro to test for equality is called BOOST_VMD_EQUAL and it has two required | |
15 | parameters which are the two values against which to test. The values can be any | |
16 | VMD data type. | |
17 | ||
18 | For the composite data types of array, list, seq, and tuple, or any of those types | |
19 | in a multi-element sequence, the elements of those types must also be a data type | |
20 | which VMD can parse. BOOST_VMD_EQUAL recursively parses the elements in a composite data type | |
21 | for equality, up to a level of 16 inner types, to test that one composite type | |
22 | equals another composite type. The requirement, that composite elements must also | |
23 | be a data type which VMD can parse, is different from most other macros | |
24 | in the VMD library, where only the top-level composite type need be parsed enough to | |
25 | determine the type of the data. If BOOST_VMD_EQUAL encounters a data type which it | |
26 | cannot parse the result will be UB. | |
27 | ||
28 | VMD identifiers used in equality testing must be registered and pre-detected. | |
29 | All numbers and v-types are already registered/pre-detected for equality testing | |
30 | so it is only user-defined identifiers which must be registered and pre-detected. | |
31 | If an identifier has not been both registered and predetected it will never be | |
32 | equal to the same identifier value, so it will always fail equality testing, | |
33 | although it will not give a preprocessing error doing so. | |
34 | ||
35 | The BOOST_VMD_EQUAL macro returns 1 if both parameters are equal and 0 if the | |
36 | parameters are not equal. | |
37 | ||
38 | Conversely to test for inequality, of the same values as are required in testing | |
39 | for equality, the VMD library has the macro BOOST_VMD_NOT_EQUAL. This macro is simply | |
40 | a complement of the BOOST_VMD_EQUAL macro. If BOOST_VMD_EQUAL returns 1 then | |
41 | BOOST_VMD_NOT_EQUAL returns 0 and if BOOST_VMD_EQUAL returns 0 then | |
42 | BOOST_VMD_NOT_EQUAL returns 1. | |
43 | ||
44 | The 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 | ||
82 | When BOOST_VMD_EQUAL tests for equality it always parses data for their most | |
83 | specific types. The reason for this is that a valid tuple, which is also an invalid | |
84 | list or array, can never be compared completely because all elements of that tuple | |
85 | are not data types which VMD can parse. Therefore VMD always tests equality based | |
86 | on the most specific type for any value being tested, which speeds up testing for | |
87 | the 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 | ||
109 | All of the constructs above are valid tuples. | |
110 | ||
111 | The first three are valid arrays, so they will be parsed and compared | |
112 | as 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 | ||
119 | The next three are valid lists, so they will be parsed and compared | |
120 | as 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 | ||
127 | The next three are valid lists or arrays but will be parsed as lists | |
128 | because 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 | ||
135 | The next three are valid tuples but invalid arrays. The BOOST_VMD_EQUAL | |
136 | macro attempts to parse them as the most specific type they can be, which is an | |
137 | array. But the attempt to parse them as arrays will lead to UB | |
138 | because the number which signifies the size of the array is invalid as | |
139 | a number. Now let us suppose we should parse them as the less specific type | |
140 | of a tuple instead of as an array. This will still give UB | |
141 | if we will attempt to compare the first tuple element against a corresponding | |
142 | first tuple element of another tuple, and when we do will again encounter UB | |
143 | because 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 | ||
150 | The next three are valid tuples but invalid lists. The BOOST_VMD_EQUAL | |
151 | macro attempts to parse them as the most specific type they can be, which is | |
152 | a list. But the attempt to parse them as lists will lead to UB | |
153 | because the identifier which signifies the end-of-list is invalid as | |
154 | an identifier. Now let us suppose we should parse them as the less specific type | |
155 | of a tuple instead of as a list. This will still give UB | |
156 | if we will attempt to compare the second tuple element against a corresponding | |
157 | second tuple element of another tuple, and when we do will again encounter UB | |
158 | because 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 | ||
165 | It is possible that a composite data type which has an element which VMD cannot parse | |
166 | will not give UB when compared for equality, but rather just the test for equality | |
167 | will fail. This can occur if the algorithm which tests for equality tests false before parsing of | |
168 | the 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 | ||
177 | The reason the above correctly returns 0, rather than generate UB when | |
178 | VMD attempts to parse '"astring"', which is not a data type VMD can parse, is because the | |
179 | algorithm for testing equality tests whether or not the tuples have the same number of elements | |
180 | before it tests for the equality of each element. This is just one example where testing for | |
181 | equality may fail before UB is generated when BOOST_VMD_EQUAL attempts to | |
182 | parse a data type which it cannot handle. Nevertheless the general rule should still be considered | |
183 | that for BOOST_VMD_EQUAL/BOOT_VMD_NOT_EQUAL all data types, even an element of a composite data | |
184 | type, must be a VMD data type if the macro is to work properly, else UB could occur. | |
185 | ||
186 | [heading Usage] | |
187 | ||
188 | You can use the general header file: | |
189 | ||
190 | #include <boost/vmd/vmd.hpp> | |
191 | ||
192 | or 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] |