Peng Liu c5195ae2d0
[libc++] Fix {std, ranges}::equal for vector<bool> with small storage types (#130394)
The current implementation of `{std, ranges}::equal` fails to correctly
compare `vector<bool>`s when the underlying storage type is smaller than
`int` (e.g., `unsigned char`, `unsigned short`, `uint8_t` and
`uint16_t`). See [demo](https://godbolt.org/z/j4s87s6b3)). The problem
arises due to integral promotions on the intermediate bitwise
operations, leading to incorrect final equality comparison results. This
patch fixes the issue by ensuring that `{std, ranges}::equal` operate
properly for both aligned and unaligned bits.
 
Fixes #126369.
2025-03-19 11:51:21 -04:00

72 lines
2.5 KiB
C++

//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP___VECTOR_COMPARISON_H
#define _LIBCPP___VECTOR_COMPARISON_H
#include <__algorithm/equal.h>
#include <__algorithm/lexicographical_compare.h>
#include <__algorithm/lexicographical_compare_three_way.h>
#include <__compare/synth_three_way.h>
#include <__config>
#include <__fwd/vector.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI bool
operator==(const vector<_Tp, _Allocator>& __x, const vector<_Tp, _Allocator>& __y) {
const typename vector<_Tp, _Allocator>::size_type __sz = __x.size();
return __sz == __y.size() && std::equal(__x.begin(), __x.end(), __y.begin());
}
#if _LIBCPP_STD_VER <= 17
template <class _Tp, class _Allocator>
inline _LIBCPP_HIDE_FROM_ABI bool operator!=(const vector<_Tp, _Allocator>& __x, const vector<_Tp, _Allocator>& __y) {
return !(__x == __y);
}
template <class _Tp, class _Allocator>
inline _LIBCPP_HIDE_FROM_ABI bool operator<(const vector<_Tp, _Allocator>& __x, const vector<_Tp, _Allocator>& __y) {
return std::lexicographical_compare(__x.begin(), __x.end(), __y.begin(), __y.end());
}
template <class _Tp, class _Allocator>
inline _LIBCPP_HIDE_FROM_ABI bool operator>(const vector<_Tp, _Allocator>& __x, const vector<_Tp, _Allocator>& __y) {
return __y < __x;
}
template <class _Tp, class _Allocator>
inline _LIBCPP_HIDE_FROM_ABI bool operator>=(const vector<_Tp, _Allocator>& __x, const vector<_Tp, _Allocator>& __y) {
return !(__x < __y);
}
template <class _Tp, class _Allocator>
inline _LIBCPP_HIDE_FROM_ABI bool operator<=(const vector<_Tp, _Allocator>& __x, const vector<_Tp, _Allocator>& __y) {
return !(__y < __x);
}
#else // _LIBCPP_STD_VER <= 17
template <class _Tp, class _Allocator>
_LIBCPP_HIDE_FROM_ABI constexpr __synth_three_way_result<_Tp>
operator<=>(const vector<_Tp, _Allocator>& __x, const vector<_Tp, _Allocator>& __y) {
return std::lexicographical_compare_three_way(__x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way);
}
#endif // _LIBCPP_STD_VER <= 17
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP___VECTOR_COMPARISON_H