Provide algorithms to compare iterator-ranges of elements.
More...
Detailed Description
- Outline
-
-
- Purpose:
- Provide algorithms to compare iterator-ranges of elements.
-
- Classes:
-
- See also:
- Component bslmf_isbitwiseequalitycomparable
-
- Description:
- This component provides a utility
struct
, bslalg::RangeCompare
, that defines two overloaded class methods, equal
and lexicographical
, for comparing two ranges, each specified by a pair of input iterators that are compliant with the C++11 standard [24.2.3]. The equal
method determines whether two specified ranges compare equal. The lexicographical
method determines whether the first range compares lexicographically less than, equal to, or greater than the second range. Under certain circumstances, bslalg::RangeCompare::equal
and bslalg::RangeCompare::lexicographical
may perform optimized comparisons, as described below.
bslalg::RangeCompare::equal
may perform a bit-wise comparison of the two ranges when the following two criteria are met:
bslalg::RangeCompare::lexicographical
may perform a bit-wise comparison of the two ranges when the following criterion is met:
-
The input iterators are convertible to pointers to a wide or unsigned
character type.
- Note that a class having the
bslmf::IsBitwiseEqualityComparable
trait can be described as bit-wise comparable and should meet the following criteria:
-
The values represented by two objects belonging to the class are the same if and only if each of the data members in the class has the same value in both objects.
-
The class layout includes no padding.
-
The class has no virtual members.
- Note that this component is for use primarily by the
bslstl
package. Other clients should use the STL algorithms (in headers <bsl_algorithm.h>
and <bsl_memory.h>
).
-
- Usage:
- This section illustrates intended use of this component.
-
- Example 1: Defining Equality-Comparison Operators on a Container:
- In this example we will use the
bslalg::RangeCompare::equal
class method to implement the equality-comparison operators for an iterable container type residing in the bslstl
package, and highlight the circumstances under which the optimization provided by the class method may be applied.
- Suppose that we have a new iterable container type that will be included in the
bslstl
package, and we wish to define comparison operators for the container. If the container has an iterator that provides access to the container's elements in a consistent order, and the elements themselves are equality-comparable, we can implement the container's equality-comparison operators by pair-wise comparing each of the elements over the entire range of elements in both containers. In such cases the container can use the bslalg::RangeCompare::equal
class method to equal-compare the container's elements, taking advantage of the optimizations the class method provides for bit-wise equality-comparable objects.
- First, we create an elided definition of a container class,
MyContainer
, which provides read-only iterators of the type MyContainer::ConstIterator
: template <class VALUE_TYPE>
class MyContainer {
private:
public:
typedef const VALUE_TYPE *ConstIterator;
explicit MyContainer(bslma::Allocator *basicAllocator = 0);
void push_back(const VALUE_TYPE& value);
ConstIterator begin() const;
ConstIterator end() const;
std::size_t size() const;
};
Notice that ConstIterator
is defined as a pointer type, which is one of the criteria required to enable the optimizations provided by the bslalg::RangeCompare::equal
class method.
- Then, we declare the equality-comparison operators for
MyContainer
: template <class VALUE_TYPE>
bool operator==(const MyContainer<VALUE_TYPE>& lhs,
const MyContainer<VALUE_TYPE>& rhs);
template <class VALUE_TYPE>
bool operator!=(const MyContainer<VALUE_TYPE>& lhs,
const MyContainer<VALUE_TYPE>& rhs);
Next, we implement the equality-comparison operators using bslalg::RangeCompare::equal
: template <class VALUE_TYPE>
inline
bool operator==(const MyContainer<VALUE_TYPE>& lhs,
const MyContainer<VALUE_TYPE>& rhs)
{
return BloombergLP::bslalg::RangeCompare::equal(lhs.begin(),
lhs.end(),
lhs.size(),
rhs.begin(),
rhs.end(),
rhs.size());
}
template <class VALUE_TYPE>
inline
bool operator!=(const MyContainer<VALUE_TYPE>& lhs,
const MyContainer<VALUE_TYPE>& rhs)
{
return !BloombergLP::bslalg::RangeCompare::equal(lhs.begin(),
lhs.end(),
lhs.size(),
rhs.begin(),
rhs.end(),
rhs.size());
}
Then, we create the elided definition of a value-semantic class, MyString
, together with its definition of operator==
: class MyString {
private:
char *d_start_p;
std::size_t d_length;
bslma::Allocator *d_allocator_p;
friend bool operator==(const MyString&, const MyString&);
public:
explicit MyString(const char *string,
bslma::Allocator *basicAllocator = 0);
};
bool operator==(const MyString& lhs, const MyString& rhs)
{
return lhs.d_length == rhs.d_length
&& 0 == std::strncmp(lhs.d_start_p, rhs.d_start_p, lhs.d_length);
}
Notice that MyString
is not bit-wise comparable because the address values of the d_start_p
pointer data members in two MyString
objects will be different, even if the string values of the two objects are the same.
- Next, we create two
MyContainer<MyString>
objects, and compare them using operator==
: MyContainer<MyString> c1;
MyContainer<MyString> c2;
c1.push_back(MyString("hello"));
c1.push_back(MyString("goodbye"));
c2.push_back(MyString("hello"));
c2.push_back(MyString("goodbye"));
assert(c1 == c2);
Here, the call to the bslalg::RangeCompare::equal
class method in operator==
will perform an unoptimized pair-wise comparison of the elements in c1
and c2
.
- Then, we create the elided definition of another value-semantic class,
MyPoint
, together with its definition of operator==
: class MyPoint {
private:
int d_x;
int d_y;
friend bool operator==(const MyPoint&, const MyPoint&);
public:
BSLMF_NESTED_TRAIT_DECLARATION(MyPoint,
BloombergLP::bslmf::IsBitwiseEqualityComparable);
MyPoint(int x, int y);
};
bool operator==(const MyPoint& lhs, const MyPoint& rhs)
{
return lhs.d_x == rhs.d_x && lhs.d_y == rhs.d_y;
}
Notice that the value of a MyPoint
object derives from the values of all of its data members, and that no padding is required for alignment. Furthermore, MyPoint
has no virtual methods. Therefore, MyPoint
objects are bit-wise comparable, and we can correctly declare the bslmf::IsBitwiseEqualityComparable
trait for the class, as shown above under the public TRAITS
section.
- Now, we create two
MyContainer<MyPoint>
objects and compare them using operator==
: MyContainer<MyPoint> c3;
MyContainer<MyPoint> c4;
c3.push_back(MyPoint(1, 2));
c3.push_back(MyPoint(3, 4));
c4.push_back(MyPoint(1, 2));
c4.push_back(MyPoint(3, 4));
assert(c3 == c4);
Here, the call to bslalg::RangeCompare::equal
in operator==
may take advantage of the fact that MyPoint
is bit-wise comparable and perform the comparison by directly bit-wise comparing the entire range of elements contained in the MyContainer<MyPoint>
objects. This comparison can provide a significant performance boost over the comparison between two MyContainer<MyPoint>
objects in which the nested bslmf::IsBitwiseEqualityComparable
trait is not associated with the MyPoint
class.
- Finally, note that we can instantiate
MyContainer
with int
or any other primitive type as the VALUE_TYPE
and still benefit from the optimized comparison operators, because primitive (i.e.: fundamental, enumerated, and pointer) types are inherently bit-wise comparable: MyContainer<int> c5;
MyContainer<int> c6;
c5.push_back(1);
c5.push_back(2);
c5.push_back(3);
c6.push_back(1);
c6.push_back(2);
c6.push_back(3);
assert(c5 == c6);