198 lines
8.6 KiB
Plaintext
198 lines
8.6 KiB
Plaintext
[/
|
|
(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]
|