123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- [/
- (C) Copyright Edward Diener 2011-2015
- Distributed under the Boost Software License, Version 1.0.
- (See accompanying file LICENSE_1_0.txt or copy at
- http://www.boost.org/LICENSE_1_0.txt).
- ]
- [section:vmd_assert Testing for equality and inequality]
- VMD allows the programmer to test generically for the equality or inequality
- of any value which VMD can parse. This includes emptiness, identifiers, numbers,
- types, arrays, lists, seqs, tuples, and multi-element sequences.
- The macro to test for equality is called BOOST_VMD_EQUAL and it has two required
- parameters which are the two values against which to test. The values can be any
- VMD data type.
- For the composite data types of array, list, seq, and tuple, or any of those types
- in a multi-element sequence, the elements of those types must also be a data type
- which VMD can parse. BOOST_VMD_EQUAL recursively parses the elements in a composite data type
- for equality, up to a level of 16 inner types, to test that one composite type
- equals another composite type. The requirement, that composite elements must also
- be a data type which VMD can parse, is different from most other macros
- in the VMD library, where only the top-level composite type need be parsed enough to
- determine the type of the data. If BOOST_VMD_EQUAL encounters a data type which it
- cannot parse the result will be UB.
- VMD identifiers used in equality testing must be registered and pre-detected.
- All numbers and v-types are already registered/pre-detected for equality testing
- so it is only user-defined identifiers which must be registered and pre-detected.
- If an identifier has not been both registered and predetected it will never be
- equal to the same identifier value, so it will always fail equality testing,
- although it will not give a preprocessing error doing so.
- The BOOST_VMD_EQUAL macro returns 1 if both parameters are equal and 0 if the
- parameters are not equal.
- Conversely to test for inequality, of the same values as are required in testing
- for equality, the VMD library has the macro BOOST_VMD_NOT_EQUAL. This macro is simply
- a complement of the BOOST_VMD_EQUAL macro. If BOOST_VMD_EQUAL returns 1 then
- BOOST_VMD_NOT_EQUAL returns 0 and if BOOST_VMD_EQUAL returns 0 then
- BOOST_VMD_NOT_EQUAL returns 1.
- The BOOST_VMD_EQUAL and BOOST_VMD_NOT_EQUAL macros are called "equality macros".
- #include <boost/vmd/equal.hpp>
-
- #define BOOST_VMD_REGISTER_AN_ID1 (AN_ID1)
- #define BOOST_VMD_REGISTER_AN_ID2 (AN_ID2)
-
- #define BOOST_VMD_DETECT_AN_ID1_AN_ID1
- #define BOOST_VMD_DETECT_AN_ID2_AN_ID2
-
- #define AN_IDENTIFIER1 AN_ID1
- #define AN_IDENTIFIER2 AN_ID2
- #define AN_IDENTIFIER3 AN_ID1 // same as AN_IDENTIFIER1 = AN_ID1
-
- #define A_NUMBER1 33
- #define A_NUMBER2 145
- #define A_NUMBER3 33 // same as A_NUMBER1 = 33
-
- #define A_TUPLE1 (AN_IDENTIFIER1,A_NUMBER1)
- #define A_TUPLE2 (AN_IDENTIFIER1,A_NUMBER2)
- #define A_TUPLE3 (AN_IDENTIFIER3,A_NUMBER3) // same as A_TUPLE1 = (AN_ID1,33)
-
- #define A_SEQ1 (A_NUMBER1)(A_TUPLE1)
- #define A_SEQ2 (A_NUMBER2)(A_TUPLE2)
- #define A_SEQ3 (A_NUMBER3)(A_TUPLE3) // same as A_SEQ1 = (33)((AN_ID1,33))
- BOOST_VMD_EQUAL(AN_IDENTIFIER1,AN_IDENTIFIER2) will return 0
- BOOST_VMD_EQUAL(AN_IDENTIFIER1,AN_IDENTIFIER3) will return 1
-
- BOOST_VMD_EQUAL(A_NUMBER1,A_NUMBER2) will return 0
- BOOST_VMD_EQUAL(A_NUMBER1,A_NUMBER3) will return 1
-
- BOOST_VMD_EQUAL(A_TUPLE1,A_TUPLE2) will return 0
- BOOST_VMD_EQUAL(A_TUPLE1,A_TUPLE3) will return 1
-
- BOOST_VMD_EQUAL(A_SEQ1,A_SEQ2) will return 0
- BOOST_VMD_EQUAL(A_SEQ1,A_SEQ3) will return 1
- When BOOST_VMD_EQUAL tests for equality it always parses data for their most
- specific types. The reason for this is that a valid tuple, which is also an invalid
- list or array, can never be compared completely because all elements of that tuple
- are not data types which VMD can parse. Therefore VMD always tests equality based
- on the most specific type for any value being tested, which speeds up testing for
- the more specific tuple data types such as lists and arrays.
- #define TUPLE_IS_ARRAY1 (2,(3,4))
- #define TUPLE_IS_ARRAY2 (2,(4,5))
- #define TUPLE_IS_ARRAY3 (2,(3,4))
-
- #define TUPLE_IS_LIST1 (55,BOOST_PP_NIL)
- #define TUPLE_IS_LIST2 (135,BOOST_PP_NIL)
- #define TUPLE_IS_LIST3 (55,BOOST_PP_NIL)
-
- #define TUPLE_IS_LIST_OR_ARRAY1 (2,(3,BOOST_PP_NIL))
- #define TUPLE_IS_LIST_OR_ARRAY2 (2,(4,BOOST_PP_NIL))
- #define TUPLE_IS_LIST_OR_ARRAY3 (2,(3,BOOST_PP_NIL))
-
- #define TUPLE_BUT_INVALID_ARRAY1 (&2,(3,4))
- #define TUPLE_BUT_INVALID_ARRAY2 (&2,(4,4))
- #define TUPLE_BUT_INVALID_ARRAY3 (&2,(3,4))
-
- #define TUPLE_BUT_INVALID_LIST1 (55,^BOOST_PP_NIL)
- #define TUPLE_BUT_INVALID_LIST2 (135,^BOOST_PP_NIL)
- #define TUPLE_BUT_INVALID_LIST3 (55,^BOOST_PP_NIL)
-
- All of the constructs above are valid tuples.
- The first three are valid arrays, so they will be parsed and compared
- as arrays, so that they can be used as in:
- #include <boost/vmd/equal.hpp>
-
- BOOST_VMD_EQUAL(TUPLE_IS_ARRAY1,TUPLE_IS_ARRAY2) will return 0
- BOOST_VMD_EQUAL(TUPLE_IS_ARRAY1,TUPLE_IS_ARRAY3) will return 1
-
- The next three are valid lists, so they will be parsed and compared
- as lists, so that they can be used as in:
- #include <boost/vmd/equal.hpp>
-
- BOOST_VMD_EQUAL(TUPLE_IS_LIST1,TUPLE_IS_LIST2) will return 0
- BOOST_VMD_EQUAL(TUPLE_IS_LIST1,TUPLE_IS_LIST3) will return 1
-
- The next three are valid lists or arrays but will be parsed as lists
- because lists are more specific than arrays. They can be used as in:
- #include <boost/vmd/equal.hpp>
-
- BOOST_VMD_EQUAL(TUPLE_IS_LIST_OR_ARRAY1,TUPLE_IS_LIST_OR_ARRAY2) will return 0
- BOOST_VMD_EQUAL(TUPLE_IS_LIST_OR_ARRAY1,TUPLE_IS_LIST_OR_ARRAY3) will return 1
-
- The next three are valid tuples but invalid arrays. The BOOST_VMD_EQUAL
- macro attempts to parse them as the most specific type they can be, which is an
- array. But the attempt to parse them as arrays will lead to UB
- because the number which signifies the size of the array is invalid as
- a number. Now let us suppose we should parse them as the less specific type
- of a tuple instead of as an array. This will still give UB
- if we will attempt to compare the first tuple element against a corresponding
- first tuple element of another tuple, and when we do will again encounter UB
- because it is not a data type VMD can parse.
- #include <boost/vmd/equal.hpp>
-
- BOOST_VMD_EQUAL(TUPLE_BUT_INVALID_ARRAY1,TUPLE_BUT_INVALID_ARRAY1) will generate UB
- BOOST_VMD_EQUAL(TUPLE_BUT_INVALID_ARRAY1,TUPLE_BUT_INVALID_ARRAY1) will generate UB
- The next three are valid tuples but invalid lists. The BOOST_VMD_EQUAL
- macro attempts to parse them as the most specific type they can be, which is
- a list. But the attempt to parse them as lists will lead to UB
- because the identifier which signifies the end-of-list is invalid as
- an identifier. Now let us suppose we should parse them as the less specific type
- of a tuple instead of as a list. This will still give UB
- if we will attempt to compare the second tuple element against a corresponding
- second tuple element of another tuple, and when we do will again encounter UB
- because it is not a data type VMD can parse.
- #include <boost/vmd/equal.hpp>
-
- BOOST_VMD_EQUAL(TUPLE_BUT_INVALID_LIST1,TUPLE_BUT_INVALID_LIST2) will generate UB
- BOOST_VMD_EQUAL(TUPLE_BUT_INVALID_LIST1,TUPLE_BUT_INVALID_LIST3) will generate UB
-
- It is possible that a composite data type which has an element which VMD cannot parse
- will not give UB when compared for equality, but rather just the test for equality
- will fail. This can occur if the algorithm which tests for equality tests false before parsing of
- the particular element. Such a situation might be:
- #include <boost/vmd/equal.hpp>
-
- #define A_TUPLE1 (3,4,"astring")
- #define A_TUPLE2 (3,4)
-
- BOOST_VMD_EQUAL(A_TUPLE1,A_TUPLE2) will return 0 rather than generate UB
-
- The reason the above correctly returns 0, rather than generate UB when
- VMD attempts to parse '"astring"', which is not a data type VMD can parse, is because the
- algorithm for testing equality tests whether or not the tuples have the same number of elements
- before it tests for the equality of each element. This is just one example where testing for
- equality may fail before UB is generated when BOOST_VMD_EQUAL attempts to
- parse a data type which it cannot handle. Nevertheless the general rule should still be considered
- that for BOOST_VMD_EQUAL/BOOT_VMD_NOT_EQUAL all data types, even an element of a composite data
- type, must be a VMD data type if the macro is to work properly, else UB could occur.
- [heading Usage]
- You can use the general header file:
- #include <boost/vmd/vmd.hpp>
-
- or you can use the individual header files:
- #include <boost/vmd/equal.hpp> for the BOOST_VMD_EQUAL macro
- #include <boost/vmd/not_equal.hpp> for the BOOST_VMD_NOT_EQUAL macro
-
- [endsect]
|