llvm-project/libcxx/include/__bit_reference
Nikolas Klauser 4cc8860f8f
[libc++] Refactor std::equal to forward to the 3-leg overload if the size of the ranges is known (#171585)
This allows us to merge some optimizations common between the 3-leg
overload and the two ranges overload.

In some cases this could also improve performance, since we avoid
checking one of the iterators if the size if the ranges is known. I
haven't been able to show any improvements though.

This is also a prerequisite for optimizing `std::search`.
2025-12-23 09:04:12 +01:00

736 lines
28 KiB
C++

// -*- 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___BIT_REFERENCE
#define _LIBCPP___BIT_REFERENCE
#include <__algorithm/comp.h>
#include <__algorithm/copy.h>
#include <__algorithm/copy_backward.h>
#include <__algorithm/copy_n.h>
#include <__algorithm/equal.h>
#include <__algorithm/fill_n.h>
#include <__algorithm/min.h>
#include <__algorithm/rotate.h>
#include <__algorithm/specialized_algorithms.h>
#include <__algorithm/swap_ranges.h>
#include <__assert>
#include <__bit/countr.h>
#include <__compare/ordering.h>
#include <__config>
#include <__cstddef/ptrdiff_t.h>
#include <__cstddef/size_t.h>
#include <__functional/identity.h>
#include <__fwd/bit_reference.h>
#include <__iterator/iterator_traits.h>
#include <__memory/construct_at.h>
#include <__memory/pointer_traits.h>
#include <__type_traits/conditional.h>
#include <__type_traits/desugars_to.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/is_constant_evaluated.h>
#include <__type_traits/is_same.h>
#include <__type_traits/is_unsigned.h>
#include <__type_traits/void_t.h>
#include <__utility/pair.h>
#include <__utility/swap.h>
#include <climits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
_LIBCPP_BEGIN_NAMESPACE_STD
template <class _Cp>
class __bit_const_reference;
template <class _Tp>
struct __has_storage_type {
static const bool value = false;
};
template <class, class>
struct __size_difference_type_traits {
using difference_type = ptrdiff_t;
using size_type = size_t;
};
template <class _Cp>
struct __size_difference_type_traits<_Cp, __void_t<typename _Cp::difference_type, typename _Cp::size_type> > {
using difference_type = typename _Cp::difference_type;
using size_type = typename _Cp::size_type;
};
// The `__x_mask` functions are designed to work exclusively with any unsigned `_StorageType`s, including small
// integral types such as unsigned char/short, `uint8_t`, and `uint16_t`. To prevent undefined behavior or
// ambiguities due to integral promotions for the small integral types, all intermediate bitwise operations are
// explicitly cast back to the unsigned `_StorageType`.
// Creates a mask of type `_StorageType` with a specified number of leading zeros (__clz) and sets all remaining
// bits to one.
template <class _StorageType>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __trailing_mask(unsigned __clz) {
static_assert(is_unsigned<_StorageType>::value, "__trailing_mask only works with unsigned types");
return static_cast<_StorageType>(~static_cast<_StorageType>(0)) >> __clz;
}
// Creates a mask of type `_StorageType` with a specified number of trailing zeros (__ctz) and sets all remaining
// bits to one.
template <class _StorageType>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __leading_mask(unsigned __ctz) {
static_assert(is_unsigned<_StorageType>::value, "__leading_mask only works with unsigned types");
return static_cast<_StorageType>(~static_cast<_StorageType>(0)) << __ctz;
}
// Creates a mask of type `_StorageType` with a specified number of leading zeros (__clz), a specified number of
// trailing zeros (__ctz), and sets all bits in between to one.
template <class _StorageType>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __middle_mask(unsigned __clz, unsigned __ctz) {
static_assert(is_unsigned<_StorageType>::value, "__middle_mask only works with unsigned types");
return std::__leading_mask<_StorageType>(__ctz) & std::__trailing_mask<_StorageType>(__clz);
}
// This function is designed to operate correctly even for smaller integral types like `uint8_t`, `uint16_t`,
// or `unsigned short`.
// See https://github.com/llvm/llvm-project/pull/122410.
template <class _StoragePointer>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void
__fill_masked_range(_StoragePointer __word, unsigned __clz, unsigned __ctz, bool __fill_val) {
static_assert(is_unsigned<typename pointer_traits<_StoragePointer>::element_type>::value,
"__fill_masked_range must be called with unsigned type");
using _StorageType = typename pointer_traits<_StoragePointer>::element_type;
_LIBCPP_ASSERT_VALID_INPUT_RANGE(
__ctz + __clz < sizeof(_StorageType) * CHAR_BIT, "__fill_masked_range called with invalid range");
_StorageType __m = std::__middle_mask<_StorageType>(__clz, __ctz);
if (__fill_val)
*__word |= __m;
else
*__word &= ~__m;
}
template <class _Cp, bool = __has_storage_type<_Cp>::value>
class __bit_reference {
using __storage_type _LIBCPP_NODEBUG = typename _Cp::__storage_type;
using __storage_pointer _LIBCPP_NODEBUG = typename _Cp::__storage_pointer;
__storage_pointer __seg_;
__storage_type __mask_;
friend typename _Cp::__self;
friend class __bit_const_reference<_Cp>;
friend class __bit_iterator<_Cp, false>;
public:
using __container _LIBCPP_NODEBUG = typename _Cp::__self;
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_reference(const __bit_reference&) = default;
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 operator bool() const _NOEXCEPT {
return static_cast<bool>(*__seg_ & __mask_);
}
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool operator~() const _NOEXCEPT {
return !static_cast<bool>(*this);
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_reference& operator=(bool __x) _NOEXCEPT {
if (__x)
*__seg_ |= __mask_;
else
*__seg_ &= ~__mask_;
return *this;
}
#if _LIBCPP_STD_VER >= 23
_LIBCPP_HIDE_FROM_ABI constexpr const __bit_reference& operator=(bool __x) const noexcept {
if (__x)
*__seg_ |= __mask_;
else
*__seg_ &= ~__mask_;
return *this;
}
#endif
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_reference& operator=(const __bit_reference& __x) _NOEXCEPT {
return operator=(static_cast<bool>(__x));
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void flip() _NOEXCEPT { *__seg_ ^= __mask_; }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator<_Cp, false> operator&() const _NOEXCEPT {
return __bit_iterator<_Cp, false>(__seg_, static_cast<unsigned>(std::__countr_zero(__mask_)));
}
private:
_LIBCPP_HIDE_FROM_ABI
_LIBCPP_CONSTEXPR_SINCE_CXX20 explicit __bit_reference(__storage_pointer __s, __storage_type __m) _NOEXCEPT
: __seg_(__s),
__mask_(__m) {}
};
template <class _Cp>
class __bit_reference<_Cp, false> {};
template <class _Cp>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
swap(__bit_reference<_Cp> __x, __bit_reference<_Cp> __y) _NOEXCEPT {
bool __t = __x;
__x = __y;
__y = __t;
}
template <class _Cp, class _Dp>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
swap(__bit_reference<_Cp> __x, __bit_reference<_Dp> __y) _NOEXCEPT {
bool __t = __x;
__x = __y;
__y = __t;
}
template <class _Cp>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void swap(__bit_reference<_Cp> __x, bool& __y) _NOEXCEPT {
bool __t = __x;
__x = __y;
__y = __t;
}
template <class _Cp>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void swap(bool& __x, __bit_reference<_Cp> __y) _NOEXCEPT {
bool __t = __x;
__x = __y;
__y = __t;
}
template <class _Cp>
class __bit_const_reference {
using __storage_type _LIBCPP_NODEBUG = typename _Cp::__storage_type;
using __storage_pointer _LIBCPP_NODEBUG = typename _Cp::__const_storage_pointer;
__storage_pointer __seg_;
__storage_type __mask_;
friend typename _Cp::__self;
friend class __bit_iterator<_Cp, true>;
public:
using __container _LIBCPP_NODEBUG = typename _Cp::__self;
_LIBCPP_HIDE_FROM_ABI __bit_const_reference(const __bit_const_reference&) = default;
__bit_const_reference& operator=(const __bit_const_reference&) = delete;
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_const_reference(const __bit_reference<_Cp>& __x) _NOEXCEPT
: __seg_(__x.__seg_),
__mask_(__x.__mask_) {}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR operator bool() const _NOEXCEPT {
return static_cast<bool>(*__seg_ & __mask_);
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator<_Cp, true> operator&() const _NOEXCEPT {
return __bit_iterator<_Cp, true>(__seg_, static_cast<unsigned>(std::__countr_zero(__mask_)));
}
private:
_LIBCPP_HIDE_FROM_ABI
_LIBCPP_CONSTEXPR explicit __bit_const_reference(__storage_pointer __s, __storage_type __m) _NOEXCEPT
: __seg_(__s),
__mask_(__m) {}
};
template <class _Cp>
struct __bit_array {
using difference_type _LIBCPP_NODEBUG = typename __size_difference_type_traits<_Cp>::difference_type;
using __storage_type _LIBCPP_NODEBUG = typename _Cp::__storage_type;
using __storage_pointer _LIBCPP_NODEBUG = typename _Cp::__storage_pointer;
using iterator _LIBCPP_NODEBUG = typename _Cp::iterator;
static const unsigned __bits_per_word = _Cp::__bits_per_word;
static const unsigned _Np = 4;
difference_type __size_;
__storage_type __word_[_Np];
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static difference_type capacity() {
return static_cast<difference_type>(_Np * __bits_per_word);
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit __bit_array(difference_type __s) : __size_(__s) {
if (__libcpp_is_constant_evaluated()) {
for (size_t __i = 0; __i != __bit_array<_Cp>::_Np; ++__i)
std::__construct_at(__word_ + __i, 0);
}
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator begin() {
return iterator(pointer_traits<__storage_pointer>::pointer_to(__word_[0]), 0);
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator end() {
return iterator(pointer_traits<__storage_pointer>::pointer_to(__word_[0]) + __size_ / __bits_per_word,
static_cast<unsigned>(__size_ % __bits_per_word));
}
};
template <class _Cp, bool _IsConst, typename _Cp::__storage_type>
class __bit_iterator {
public:
using difference_type = typename __size_difference_type_traits<_Cp>::difference_type;
using value_type = bool;
using pointer = __bit_iterator;
#ifndef _LIBCPP_ABI_BITSET_VECTOR_BOOL_CONST_SUBSCRIPT_RETURN_BOOL
using reference = __conditional_t<_IsConst, __bit_const_reference<_Cp>, __bit_reference<_Cp> >;
#else
using reference = __conditional_t<_IsConst, bool, __bit_reference<_Cp> >;
#endif
using iterator_category = random_access_iterator_tag;
private:
using __storage_type _LIBCPP_NODEBUG = typename _Cp::__storage_type;
using __storage_pointer _LIBCPP_NODEBUG =
__conditional_t<_IsConst, typename _Cp::__const_storage_pointer, typename _Cp::__storage_pointer>;
static const unsigned __bits_per_word = _Cp::__bits_per_word;
__storage_pointer __seg_;
unsigned __ctz_;
public:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator() _NOEXCEPT
#if _LIBCPP_STD_VER >= 14
: __seg_(nullptr),
__ctz_(0)
#endif
{
}
#ifdef _LIBCPP_ABI_TRIVIALLY_COPYABLE_BIT_ITERATOR
template <bool _IsConstDep = _IsConst, __enable_if_t<_IsConstDep, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator(const __bit_iterator<_Cp, false>& __it) _NOEXCEPT
: __seg_(__it.__seg_),
__ctz_(__it.__ctz_) {}
_LIBCPP_HIDE_FROM_ABI __bit_iterator(const __bit_iterator&) = default;
_LIBCPP_HIDE_FROM_ABI __bit_iterator& operator=(const __bit_iterator&) = default;
#else
// When _IsConst=false, this is the copy constructor.
// It is non-trivial. Making it trivial would break ABI.
// When _IsConst=true, this is a converting constructor;
// the copy and move constructors are implicitly generated
// and trivial.
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator(const __bit_iterator<_Cp, false>& __it) _NOEXCEPT
: __seg_(__it.__seg_),
__ctz_(__it.__ctz_) {}
// When _IsConst=false, we have a user-provided copy constructor,
// so we must also provide a copy assignment operator because
// the implicit generation of a defaulted one is deprecated.
// When _IsConst=true, the assignment operators are
// implicitly generated and trivial.
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator&
operator=(const _If<_IsConst, struct __private_nat, __bit_iterator>& __it) {
__seg_ = __it.__seg_;
__ctz_ = __it.__ctz_;
return *this;
}
#endif
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference operator*() const _NOEXCEPT {
_LIBCPP_ASSERT_INTERNAL(__ctz_ < __bits_per_word, "Dereferencing an invalid __bit_iterator.");
return __conditional_t<_IsConst, __bit_const_reference<_Cp>, __bit_reference<_Cp> >(
__seg_, __storage_type(1) << __ctz_);
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator& operator++() {
if (__ctz_ != __bits_per_word - 1)
++__ctz_;
else {
__ctz_ = 0;
++__seg_;
}
return *this;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator operator++(int) {
__bit_iterator __tmp = *this;
++(*this);
return __tmp;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator& operator--() {
if (__ctz_ != 0)
--__ctz_;
else {
__ctz_ = __bits_per_word - 1;
--__seg_;
}
return *this;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator operator--(int) {
__bit_iterator __tmp = *this;
--(*this);
return __tmp;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator& operator+=(difference_type __n) {
if (__n >= 0)
__seg_ += (__n + __ctz_) / __bits_per_word;
else
__seg_ += static_cast<difference_type>(__n - __bits_per_word + __ctz_ + 1) /
static_cast<difference_type>(__bits_per_word);
__n &= (__bits_per_word - 1);
__ctz_ = static_cast<unsigned>((__n + __ctz_) % __bits_per_word);
return *this;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator& operator-=(difference_type __n) {
return *this += -__n;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator operator+(difference_type __n) const {
__bit_iterator __t(*this);
__t += __n;
return __t;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator operator-(difference_type __n) const {
__bit_iterator __t(*this);
__t -= __n;
return __t;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator
operator+(difference_type __n, const __bit_iterator& __it) {
return __it + __n;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend difference_type
operator-(const __bit_iterator& __x, const __bit_iterator& __y) {
return (__x.__seg_ - __y.__seg_) * __bits_per_word + __x.__ctz_ - __y.__ctz_;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference operator[](difference_type __n) const {
return *(*this + __n);
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool
operator==(const __bit_iterator& __x, const __bit_iterator& __y) {
return __x.__seg_ == __y.__seg_ && __x.__ctz_ == __y.__ctz_;
}
#if _LIBCPP_STD_VER <= 17
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool
operator!=(const __bit_iterator& __x, const __bit_iterator& __y) {
return !(__x == __y);
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool
operator<(const __bit_iterator& __x, const __bit_iterator& __y) {
return __x.__seg_ < __y.__seg_ || (__x.__seg_ == __y.__seg_ && __x.__ctz_ < __y.__ctz_);
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool
operator>(const __bit_iterator& __x, const __bit_iterator& __y) {
return __y < __x;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool
operator<=(const __bit_iterator& __x, const __bit_iterator& __y) {
return !(__y < __x);
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool
operator>=(const __bit_iterator& __x, const __bit_iterator& __y) {
return !(__x < __y);
}
#else // _LIBCPP_STD_VER <= 17
_LIBCPP_HIDE_FROM_ABI constexpr friend strong_ordering
operator<=>(const __bit_iterator& __x, const __bit_iterator& __y) {
if (__x.__seg_ < __y.__seg_)
return strong_ordering::less;
if (__x.__seg_ == __y.__seg_)
return __x.__ctz_ <=> __y.__ctz_;
return strong_ordering::greater;
}
#endif // _LIBCPP_STD_VER <= 17
private:
_LIBCPP_HIDE_FROM_ABI
_LIBCPP_CONSTEXPR_SINCE_CXX20 explicit __bit_iterator(__storage_pointer __s, unsigned __ctz) _NOEXCEPT
: __seg_(__s),
__ctz_(__ctz) {
_LIBCPP_ASSERT_INTERNAL(
__ctz_ < __bits_per_word, "__bit_iterator initialized with an invalid number of trailing zeros.");
}
friend typename _Cp::__self;
friend class __bit_reference<_Cp>;
friend class __bit_const_reference<_Cp>;
friend class __bit_iterator<_Cp, true>;
template <class _Dp>
friend struct __bit_array;
template <class _Dp, bool _IC>
_LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Dp, false> __copy_backward_aligned(
__bit_iterator<_Dp, _IC> __first, __bit_iterator<_Dp, _IC> __last, __bit_iterator<_Dp, false> __result);
template <class _Dp, bool _IC>
_LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Dp, false> __copy_backward_unaligned(
__bit_iterator<_Dp, _IC> __first, __bit_iterator<_Dp, _IC> __last, __bit_iterator<_Dp, false> __result);
template <class _AlgPolicy>
friend struct __copy_backward_impl;
template <class _Cl, class _Cr>
_LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Cr, false>
__swap_ranges_aligned(__bit_iterator<_Cl, false>, __bit_iterator<_Cl, false>, __bit_iterator<_Cr, false>);
template <class _Cl, class _Cr>
_LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Cr, false>
__swap_ranges_unaligned(__bit_iterator<_Cl, false>, __bit_iterator<_Cl, false>, __bit_iterator<_Cr, false>);
template <class, class _Cl, class _Cr>
_LIBCPP_CONSTEXPR_SINCE_CXX20 friend pair<__bit_iterator<_Cl, false>, __bit_iterator<_Cr, false> >
__swap_ranges(__bit_iterator<_Cl, false>, __bit_iterator<_Cl, false>, __bit_iterator<_Cr, false>);
template <class, class _Dp>
_LIBCPP_CONSTEXPR_SINCE_CXX20 friend pair<__bit_iterator<_Dp, false>, __bit_iterator<_Dp, false> >
__rotate(__bit_iterator<_Dp, false>, __bit_iterator<_Dp, false>, __bit_iterator<_Dp, false>);
template <class _Dp, bool _IsConst1, bool _IsConst2>
_LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool
__equal_aligned(__bit_iterator<_Dp, _IsConst1>, __bit_iterator<_Dp, _IsConst1>, __bit_iterator<_Dp, _IsConst2>);
template <class _Dp, bool _IsConst1, bool _IsConst2>
_LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool
__equal_unaligned(__bit_iterator<_Dp, _IsConst1>, __bit_iterator<_Dp, _IsConst1>, __bit_iterator<_Dp, _IsConst2>);
template <class _Dp,
bool _IsConst1,
bool _IsConst2,
class _BinaryPredicate,
class _Proj1,
class _Proj2,
__enable_if_t<__is_identity<_Proj1>::value && __is_identity<_Proj2>::value &&
__desugars_to_v<__equal_tag, _BinaryPredicate, bool, bool>,
int> >
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool __equal_iter_impl(
__bit_iterator<_Dp, _IsConst1>,
__bit_iterator<_Dp, _IsConst1>,
__bit_iterator<_Dp, _IsConst2>,
_BinaryPredicate,
_Proj1&,
_Proj2&);
template <bool,
class _Dp,
bool _IsConst1,
bool _IsConst2,
class _Pred,
class _Proj1,
class _Proj2,
__enable_if_t<__desugars_to_v<__equal_tag, _Pred, bool, bool> && __is_identity<_Proj1>::value &&
__is_identity<_Proj2>::value,
int> >
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool __equal_impl(
__bit_iterator<_Dp, _IsConst1> __first1,
__bit_iterator<_Dp, _IsConst1> __last1,
__bit_iterator<_Dp, _IsConst2> __first2,
__bit_iterator<_Dp, _IsConst2>,
_Pred&,
_Proj1&,
_Proj2&);
template <bool _ToFind, class _Dp, bool _IC>
_LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Dp, _IC>
__find_bool(__bit_iterator<_Dp, _IC>, typename __size_difference_type_traits<_Dp>::size_type);
template <bool _ToCount, class _Dp, bool _IC>
friend typename __bit_iterator<_Dp, _IC>::difference_type _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
__count_bool(__bit_iterator<_Dp, _IC>, typename __size_difference_type_traits<_Dp>::size_type);
template <class, class...>
friend struct __specialized_algorithm;
};
template <class _Cp>
struct __specialized_algorithm<_Algorithm::__fill_n, __single_iterator<__bit_iterator<_Cp, false> > > {
static const bool __has_algorithm = true;
template <bool _FillVal>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static void
__impl(__bit_iterator<_Cp, false> __first, typename __size_difference_type_traits<_Cp>::size_type __n) {
using _It = __bit_iterator<_Cp, false>;
using __storage_type = typename _It::__storage_type;
const int __bits_per_word = _It::__bits_per_word;
// do first partial word
if (__first.__ctz_ != 0) {
__storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_);
__storage_type __dn = std::min(__clz_f, __n);
std::__fill_masked_range(std::__to_address(__first.__seg_), __clz_f - __dn, __first.__ctz_, _FillVal);
__n -= __dn;
++__first.__seg_;
}
// do middle whole words
__storage_type __nw = __n / __bits_per_word;
std::__fill_n(std::__to_address(__first.__seg_), __nw, _FillVal ? static_cast<__storage_type>(-1) : 0);
__n -= __nw * __bits_per_word;
// do last partial word
if (__n > 0) {
__first.__seg_ += __nw;
std::__fill_masked_range(std::__to_address(__first.__seg_), __bits_per_word - __n, 0u, _FillVal);
}
}
template <class _Size, class _Tp>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static __bit_iterator<_Cp, false>
operator()(__bit_iterator<_Cp, false> __first, _Size __n, const _Tp& __value) {
if (__n > 0) {
if (__value)
__impl<true>(__first, __n);
else
__impl<false>(__first, __n);
}
return __first + __n;
}
};
template <class _Cp, bool _IsConst>
struct __specialized_algorithm<_Algorithm::__copy,
__iterator_pair<__bit_iterator<_Cp, _IsConst>, __bit_iterator<_Cp, _IsConst> >,
__single_iterator<__bit_iterator<_Cp, false> > > {
static const bool __has_algorithm = true;
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static __bit_iterator<_Cp, false>
__aligned_impl(__bit_iterator<_Cp, _IsConst> __first,
__bit_iterator<_Cp, _IsConst> __last,
__bit_iterator<_Cp, false> __result) {
using _In = __bit_iterator<_Cp, _IsConst>;
using difference_type = typename _In::difference_type;
using __storage_type = typename _In::__storage_type;
const int __bits_per_word = _In::__bits_per_word;
difference_type __n = __last - __first;
if (__n > 0) {
// do first word
if (__first.__ctz_ != 0) {
unsigned __clz = __bits_per_word - __first.__ctz_;
difference_type __dn = std::min(static_cast<difference_type>(__clz), __n);
__n -= __dn;
__storage_type __m = std::__middle_mask<__storage_type>(__clz - __dn, __first.__ctz_);
__storage_type __b = *__first.__seg_ & __m;
*__result.__seg_ &= ~__m;
*__result.__seg_ |= __b;
__result.__seg_ += (__dn + __result.__ctz_) / __bits_per_word;
__result.__ctz_ = static_cast<unsigned>((__dn + __result.__ctz_) % __bits_per_word);
++__first.__seg_;
// __first.__ctz_ = 0;
}
// __first.__ctz_ == 0;
// do middle words
__storage_type __nw = __n / __bits_per_word;
std::copy(std::__to_address(__first.__seg_),
std::__to_address(__first.__seg_ + __nw),
std::__to_address(__result.__seg_));
__n -= __nw * __bits_per_word;
__result.__seg_ += __nw;
// do last word
if (__n > 0) {
__first.__seg_ += __nw;
__storage_type __m = std::__trailing_mask<__storage_type>(__bits_per_word - __n);
__storage_type __b = *__first.__seg_ & __m;
*__result.__seg_ &= ~__m;
*__result.__seg_ |= __b;
__result.__ctz_ = static_cast<unsigned>(__n);
}
}
return __result;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static __bit_iterator<_Cp, false>
__unaligned_impl(__bit_iterator<_Cp, _IsConst> __first,
__bit_iterator<_Cp, _IsConst> __last,
__bit_iterator<_Cp, false> __result) {
using _In = __bit_iterator<_Cp, _IsConst>;
using difference_type = typename _In::difference_type;
using __storage_type = typename _In::__storage_type;
const int __bits_per_word = _In::__bits_per_word;
difference_type __n = __last - __first;
if (__n > 0) {
// do first word
if (__first.__ctz_ != 0) {
unsigned __clz_f = __bits_per_word - __first.__ctz_;
difference_type __dn = std::min(static_cast<difference_type>(__clz_f), __n);
__n -= __dn;
__storage_type __m = std::__middle_mask<__storage_type>(__clz_f - __dn, __first.__ctz_);
__storage_type __b = *__first.__seg_ & __m;
unsigned __clz_r = __bits_per_word - __result.__ctz_;
__storage_type __ddn = std::min<__storage_type>(__dn, __clz_r);
__m = std::__middle_mask<__storage_type>(__clz_r - __ddn, __result.__ctz_);
*__result.__seg_ &= ~__m;
if (__result.__ctz_ > __first.__ctz_)
*__result.__seg_ |= __b << (__result.__ctz_ - __first.__ctz_);
else
*__result.__seg_ |= __b >> (__first.__ctz_ - __result.__ctz_);
__result.__seg_ += (__ddn + __result.__ctz_) / __bits_per_word;
__result.__ctz_ = static_cast<unsigned>((__ddn + __result.__ctz_) % __bits_per_word);
__dn -= __ddn;
if (__dn > 0) {
__m = std::__trailing_mask<__storage_type>(__bits_per_word - __dn);
*__result.__seg_ &= ~__m;
*__result.__seg_ |= __b >> (__first.__ctz_ + __ddn);
__result.__ctz_ = static_cast<unsigned>(__dn);
}
++__first.__seg_;
// __first.__ctz_ = 0;
}
// __first.__ctz_ == 0;
// do middle words
unsigned __clz_r = __bits_per_word - __result.__ctz_;
__storage_type __m = std::__leading_mask<__storage_type>(__result.__ctz_);
for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first.__seg_) {
__storage_type __b = *__first.__seg_;
*__result.__seg_ &= ~__m;
*__result.__seg_ |= __b << __result.__ctz_;
++__result.__seg_;
*__result.__seg_ &= __m;
*__result.__seg_ |= __b >> __clz_r;
}
// do last word
if (__n > 0) {
__m = std::__trailing_mask<__storage_type>(__bits_per_word - __n);
__storage_type __b = *__first.__seg_ & __m;
__storage_type __dn = std::min(__n, static_cast<difference_type>(__clz_r));
__m = std::__middle_mask<__storage_type>(__clz_r - __dn, __result.__ctz_);
*__result.__seg_ &= ~__m;
*__result.__seg_ |= __b << __result.__ctz_;
__result.__seg_ += (__dn + __result.__ctz_) / __bits_per_word;
__result.__ctz_ = static_cast<unsigned>((__dn + __result.__ctz_) % __bits_per_word);
__n -= __dn;
if (__n > 0) {
__m = std::__trailing_mask<__storage_type>(__bits_per_word - __n);
*__result.__seg_ &= ~__m;
*__result.__seg_ |= __b >> __dn;
__result.__ctz_ = static_cast<unsigned>(__n);
}
}
}
return __result;
}
_LIBCPP_HIDE_FROM_ABI
_LIBCPP_CONSTEXPR_SINCE_CXX20 static pair<__bit_iterator<_Cp, _IsConst>, __bit_iterator<_Cp, false> >
operator()(__bit_iterator<_Cp, _IsConst> __first,
__bit_iterator<_Cp, _IsConst> __last,
__bit_iterator<_Cp, false> __result) {
if (__first.__ctz_ == __result.__ctz_)
return std::make_pair(__last, __aligned_impl(__first, __last, __result));
return std::make_pair(__last, __unaligned_impl(__first, __last, __result));
}
};
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
#endif // _LIBCPP___BIT_REFERENCE