• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PeterCDMcLean / BitLib / 15574317715

11 Jun 2025 02:02AM UTC coverage: 53.774% (+1.0%) from 52.785%
15574317715

Pull #16

github

web-flow
Merge c4534fd50 into a32e9aeba
Pull Request #16: Small buffer optimization

9875 of 18300 branches covered (53.96%)

Branch coverage included in aggregate %.

619 of 655 new or added lines in 16 files covered. (94.5%)

2 existing lines in 1 file now uncovered.

5912 of 11058 relevant lines covered (53.46%)

7914739.4 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

68.8
/include/bitlib/bit-iterator/bit_details.hpp
1
// ============================== BIT DETAILS =============================== //
2
// Project:         The C++ Bit Library
3
// Name:            bit_details.hpp
4
// Description:     Provides common implementation details and helper classes
5
// Creator:         Vincent Reverdy
6
// Contributor(s):  Vincent Reverdy [2015-2017]
7
//                  Bryce Kille [2019]
8
// License:         BSD 3-Clause License
9
// ========================================================================== //
10
#ifndef _BIT_DETAILS_HPP_INCLUDED
11
#define _BIT_DETAILS_HPP_INCLUDED
12
// ========================================================================== //
13

14

15

16
// ================================ PREAMBLE ================================ //
17
// C++ standard library
18
#include <immintrin.h>
19

20
#include <algorithm>
21
#include <cassert>
22
#include <concepts>
23
#include <cstddef>
24
#include <cstdint>
25
#include <iterator>
26
#include <limits>
27
#include <ranges>
28
#include <stdexcept>
29
#include <tuple>
30
#include <type_traits>
31
#include <utility>
32

33
#include "bitlib/bit-containers/bit_bitsof.hpp"
34
#include "bitlib/bit_concepts.hpp"
35

36
// Project sources
37
// Third-party libraries
38
// Miscellaneous
39
namespace bit {
40
class bit_value;
41
template <class WordType>
42
class bit_reference;
43
template <class Iterator>
44
class bit_iterator;
45
template <class WordType>
46
using bit_pointer = bit_iterator<WordType*>;
47
template <typename target_word_ptr, typename source_word_ptr>
48
class bit_word_pointer_adapter;
49

50
// ========================================================================== //
51

52
/* ***************************** BINARY DIGITS ****************************** */
53
// Binary digits structure definition
54
// Implementation template: only instantiates static_asserts for non-byte types.
55
template <typename T, bool = std::is_same<T, std::byte>::value>
56
struct binary_digits_impl : std::integral_constant<std::size_t, std::numeric_limits<std::make_unsigned_t<T>>::digits> {
57
  static_assert(std::is_integral<T>::value, "Type must be integral");
58
  //static_assert(std::is_unsigned<T>::value, "Type must be unsigned");
59
  static_assert(!std::is_same<T, bool>::value, "Type must not be bool");
60
  static_assert(!std::is_same<T, char>::value, "Type must not be char");
61
};
62

63
// Specialization for std::byte.
64
template <>
65
struct binary_digits_impl<std::byte, true> : std::integral_constant<std::size_t, std::numeric_limits<unsigned char>::digits> {};
66

67
// Public interface that removes cv-qualifiers.
68
template <typename UIntType>
69
struct binary_digits : binary_digits_impl<std::remove_cv_t<UIntType>> {};
70

71
// Binary digits value
72
template <class T>
73
constexpr std::size_t binary_digits_v = binary_digits<T>::value;
74
/*************************************************************************** */
75

76
template <size_t N>
77
using ceil_integral = std::conditional_t<
78
    (N <= bitsof<std::uint8_t>()),
79
    std::uint8_t,
80
    std::conditional_t<
81
        (N <= bitsof<std::uint16_t>()),
82
        std::uint16_t,
83
        std::conditional_t<
84
            (N <= bitsof<std::uint32_t>()),
85
            std::uint32_t,
86
            std::conditional_t<
87
                (N <= bitsof<std::uint64_t>()),
88
                std::uint64_t,
89
                std::uint64_t>>>>;
90

91
/* *************** IMPLEMENTATION DETAILS: CV ITERATOR TRAITS *************** */
92
// Cv iterator traits structure definition
93
template <class Iterator>
94
struct _cv_iterator_traits
95
{
96
    // Assertions
97
    private:
98
    using _traits_t = std::iterator_traits<Iterator>;
99
    using _difference_t = typename _traits_t::difference_type;
100
    using _value_t = typename _traits_t::value_type;
101
    using _pointer_t = typename _traits_t::pointer;
102
    using _reference_t = typename _traits_t::reference;
103
    using _category_t =  typename _traits_t::iterator_category;
104
    using _no_pointer_t = typename std::remove_pointer<_pointer_t>::type;
105
    using _no_reference_t = typename std::remove_reference<_reference_t>::type;
106
    using _raw_value_t = typename std::remove_cv<_value_t>::type;
107
    using _raw_pointer_t = typename std::remove_cv<_no_pointer_t>::type;
108
    using _raw_reference_t = typename std::remove_cv<_no_reference_t>::type;
109
    using _cv_value_t = _no_reference_t;
110

111
    //    static_assert(std::is_same<_raw_pointer_t, _raw_value_t>::value, "");
112
    //    static_assert(std::is_same<_raw_reference_t, _raw_value_t>::value, "");
113

114
    // Types
115
    public:
116
    using difference_type = _difference_t;
117
    using value_type = _cv_value_t;
118
    using pointer = _pointer_t;
119
    using reference = _reference_t;
120
    using iterator_category = _category_t;
121
};
122
/* ************************************************************************** */
123

124
#if 0
125
/* *********** IMPLEMENTATION DETAILS: NARROWEST AND WIDEST TYPES *********** */
126
// Narrowest type structure declaration
127
template <class... T>
128
struct _narrowest_type;
129

130
// Narrowest type structure specialization: selects the only passed type
131
template <class T>
132
struct _narrowest_type<T>
133
: std::common_type<T>
134
{
135
    static_assert(binary_digits<T>::value, "");
136
};
137

138
// Narrowest type structure specialization: selects the type with less bits
139
template <class T, class U>
140
struct _narrowest_type<T, U>
141
: _narrowest_type<
142
    typename std::conditional<
143
        (binary_digits<T>::value < binary_digits<U>::value),
144
        T,
145
        typename std::conditional<
146
            (binary_digits<T>::value > binary_digits<U>::value),
147
            U,
148
            typename std::common_type<T, U>::type
149
        >::type
150
    >::type
151
>
152
{
153
};
154

155
// Narrowest type structure specialization: recursively selects the right type
156
template <class T, class... U>
157
struct _narrowest_type<T, U...>
158
: _narrowest_type<T, typename _narrowest_type<U...>::type>
159
{
160
};
161

162
// Narrowest type alias
163
template <class... T>
164
using _narrowest_type_t = typename _narrowest_type<T...>::type;
165

166
// Widest type structure declaration
167
template <class... X>
168
struct _widest_type;
169

170
// Widest type structure specialization: selects the only passed type
171
template <class T>
172
struct _widest_type<T>
173
: std::common_type<T>
174
{
175
    static_assert(binary_digits<T>::value, "");
176
};
177

178
// Widest type structure specialization: selects the type with more bits
179
template <class T, class U>
180
struct _widest_type<T, U>
181
: _widest_type<
182
    typename std::conditional<
183
        (binary_digits<T>::value > binary_digits<U>::value),
184
        T,
185
        typename std::conditional<
186
            (binary_digits<T>::value < binary_digits<U>::value),
187
            U,
188
            typename std::common_type<T, U>::type
189
        >::type
190
    >::type
191
>
192
{
193
};
194

195
// Widest type structure specialization: recursively selects the right type
196
template <class T, class... X>
197
struct _widest_type<T, X...>
198
: _widest_type<T, typename _widest_type<X...>::type>
199
{
200
};
201

202
// Widest type alias
203
template <class... T>
204
using _widest_type_t = typename _widest_type<T...>::type;
205
/* ************************************************************************** */
206

207

208

209
/* ************ IMPLEMENTATION DETAILS: NARROWER AND WIDER TYPES ************ */
210
// Narrower type structure definition
211
template <class T, int I = 0>
212
struct _narrower_type
213
{
214
    using tuple = std::tuple<
215
        unsigned long long int,
216
        unsigned long int,
217
        unsigned int,
218
        unsigned short int,
219
        unsigned char
220
    >;
221
    using lhs_bits = binary_digits<T>;
222
    using rhs_bits = binary_digits<typename std::tuple_element<I, tuple>::type>;
223
    using type = typename std::conditional<
224
        (lhs_bits::value > rhs_bits::value),
225
        typename std::tuple_element<I, tuple>::type,
226
        typename std::conditional<
227
            (I + 1 < std::tuple_size<tuple>::value),
228
            typename _narrower_type<
229
                T,
230
                (I + 1 < std::tuple_size<tuple>::value ? I + 1 : -1)
231
            >::type,
232
            typename std::tuple_element<I, tuple>::type
233
        >::type
234
    >::type;
235
};
236

237
// Narrower type structure specialization: not found
238
template <class T>
239
struct _narrower_type<T, -1>
240
{
241
    using type = T;
242
};
243

244
// Narrower type alias
245
template <class T>
246
using _narrower_type_t = typename _narrower_type<T>::type;
247

248
// Wider type structure definition
249
template <class T, int I = 0>
250
struct _wider_type
251
{
252
    using tuple = std::tuple<
253
        unsigned char,
254
        unsigned short int,
255
        unsigned int,
256
        unsigned long int,
257
        unsigned long long int
258
    >;
259
    using lhs_bits = binary_digits<T>;
260
    using rhs_bits = binary_digits<typename std::tuple_element<I, tuple>::type>;
261
    using type = typename std::conditional<
262
        (lhs_bits::value < rhs_bits::value),
263
        typename std::tuple_element<I, tuple>::type,
264
        typename std::conditional<
265
            (I + 1 < std::tuple_size<tuple>::value),
266
            typename _narrower_type<
267
                T,
268
                (I + 1 < std::tuple_size<tuple>::value ? I + 1 : -1)
269
            >::type,
270
            typename std::tuple_element<I, tuple>::type
271
        >::type
272
    >::type;
273
};
274

275
// Wider type structure specialization: not found
276
template <class T>
277
struct _wider_type<T, -1>
278
{
279
    using type = T;
280
};
281

282
// Wider type alias
283
template <class T>
284
using _wider_type_t = typename _wider_type<T>::type;
285
/* ************************************************************************** */
286
#endif
287

288
/*
289
exact_ceil_integral is used to determine the exact integral type that a proxy reference
290
can be implicitly converted to.
291
If the proxy reference supports multiple types, it will pick the largest, preferring unsigned.
292
*/
293
template <typename T>
294
struct exact_ceil_integral {
295
 private:
296
  using U = std::remove_cvref_t<T>;
297

298
  template <typename From, typename To>
NEW
299
  static constexpr bool is_exactly_convertible() {
NEW
300
    if constexpr (!std::is_convertible_v<From, To>) {
NEW
301
      return false;
NEW
302
    } else {
NEW
303
      // Try brace-initialization to detect narrowing
NEW
304
      return requires(From f) {
NEW
305
        To{f};  // will fail if narrowing
NEW
306
      };
NEW
307
    }
NEW
308
  }
309

310
 public:
311
  using type = std::conditional_t<
312
      is_exactly_convertible<U, uint64_t>(), uint64_t,
313
      std::conditional_t<
314
          is_exactly_convertible<U, int64_t>(), int64_t,
315
          std::conditional_t<
316
              is_exactly_convertible<U, uint32_t>(), uint32_t,
317
              std::conditional_t<
318
                  is_exactly_convertible<U, int32_t>(), int32_t,
319
                  std::conditional_t<
320
                      is_exactly_convertible<U, uint16_t>(), uint16_t,
321
                      std::conditional_t<
322
                          is_exactly_convertible<U, int16_t>(), int16_t,
323
                          std::conditional_t<
324
                              is_exactly_convertible<U, uint8_t>(), uint8_t,
325
                              std::conditional_t<
326
                                  is_exactly_convertible<U, int8_t>(), int8_t,
327
                                  void>>>>>>>>;
328
};
329

330
// Helper alias
331
template <typename T>
332
using exact_ceil_integral_t = typename exact_ceil_integral<T>::type;
333

334
/* ******************* IMPLEMENTATION DETAILS: UTILITIES ******************** */
335
// Assertions
336
template <class Iterator>
337
constexpr bool _assert_range_viability(Iterator first, Iterator last);
338
/* ************************************************************************** */
339

340

341

342
/* ****************** IMPLEMENTATION DETAILS: INSTRUCTIONS ****************** */
343
// Population count
344
template <class T, class = decltype(__builtin_popcountll(T()))>
345
constexpr T _popcnt(T src) noexcept;
346
template <class T, class... X>
347
constexpr T _popcnt(T src, X...) noexcept;
348

349
// Leading zeros count
350
template <class T, class = decltype(__builtin_clzll(T()))>
351
constexpr T _lzcnt(T src) noexcept;
352
template <class T, class... X>
353
constexpr T _lzcnt(T src, X...) noexcept;
354

355
// Trailing zeros count
356
template <class T, class = decltype(__builtin_ctzll(T()))>
357
constexpr T _tzcnt(T src) noexcept;
358
template <class T, class... X>
359
constexpr T _tzcnt(T src, X...) noexcept;
360

361
// Bit field extraction
362
template <class T, class = decltype(__builtin_ia32_bextr_u64(T(), T(), T()))>
363
constexpr T _bextr(T src, T start, T len) noexcept;
364
template <class T, class... X>
365
constexpr T _bextr(T src, T start, T len, X...) noexcept;
366

367
#if 0
368
// Parallel bits deposit
369
template <class T, class = decltype(_pdep_u64(T()))>
370
constexpr T _pdep(T src, T msk) noexcept;
371
template <class T, class... X>
372
constexpr T _pdep(T src, T msk, X...) noexcept;
373

374
// Parallel bits extract
375
template <class T, class = decltype(_pext_u64(T()))>
376
constexpr T _pext(T src, T msk) noexcept;
377
template <class T, class... X>
378
constexpr T _pext(T src, T msk, X...) noexcept;
379

380
// Byte swap
381
template <class T, class T128 = decltype(__uint128_t(__builtin_bswap64(T())))>
382
constexpr T _byteswap(T src) noexcept;
383
template <class T, class... X>
384
constexpr T _byteswap(T src, X...) noexcept;
385

386
#endif
387

388
// Bit swap
389
template <class T>
390
constexpr T _bitswap(T src) noexcept;
391
template <class T, std::size_t N>
392
constexpr T _bitswap(T src) noexcept;
393
template <class T, std::size_t N>
394
constexpr T _bitswap() noexcept;
395

396
// Bit blend
397
template <class T>
398
constexpr T _bitblend(T src0, T src1, T msk) noexcept;
399
template <class T>
400
constexpr T _bitblend(T src0, T src1, T start, T len) noexcept;
401

402
// Bit exchange
403
template <class T>
404
constexpr void _bitexch(T& src0, T& src1, T msk) noexcept;
405
template <class T, class S>
406
constexpr void _bitexch(T& src0, T& src1, S start, S len) noexcept;
407
template <class T, class S>
408
constexpr void _bitexch(T& src0, T& src1, S start0, S start1, S len) noexcept;
409

410
// Bit compare
411
template <class T>
412
constexpr T _bitcmp(T src0, T src1, T start0, T start1, T len) noexcept;
413

414
// Double precision shift left
415
template <class T>
416
constexpr T _shld(T dst, T src, T cnt) noexcept;
417

418
// Double precision shift right
419
template <class T>
420
constexpr T _shrd(T dst, T src, T cnt) noexcept;
421

422
// Add carry
423
template <class... T>
424
using _supports_adc = decltype(__builtin_ia32_addcarryx_u64(T()...));
425
template <class C, class T, class = _supports_adc<C, T, T, std::nullptr_t>>
426
constexpr C _addcarry(C carry, T src0, T src1, T* dst) noexcept;
427
template <class C, class T, class... X>
428
constexpr C _addcarry(C carry, T src0, T src1, T* dst, X...) noexcept;
429

430
// Sub borrow
431
template <class... T>
432
using _supports_sbb = decltype(__builtin_ia32_sbb_u64(T()...));
433
template <class... T>
434
using _supports_sbb_alt = decltype(__builtin_ia32_subborrow_u64(T()...));
435
template <class B, class T, class = _supports_sbb<B, T, T, std::nullptr_t>>
436
constexpr B _subborrow(B borrow, T src0, T src1, T* dst) noexcept;
437
template <class B, class T, class = _supports_sbb_alt<B, T, T, std::nullptr_t>>
438
constexpr B _subborrow(const B& borrow, T src0, T src1, T* dst) noexcept;
439
template <class B, class T, class... X>
440
constexpr B _subborrow(B borrow, T src0, T src1, T* dst, X...) noexcept;
441

442
// Multiword multiply
443
template <class T, class T128 = decltype(__uint128_t(T()))>
444
constexpr T _mulx(T src0, T src1, T* hi) noexcept;
445
template <class T, class... X>
446
constexpr T _mulx(T src0, T src1, T* hi, X...) noexcept;
447
/* ************************************************************************** */
448

449
/*
450
Logical shift right
451
*/
452
template <std::integral T, typename size_type = size_t>
453
constexpr T lsr(const T val, const size_type shift) {
169,953,049✔
454
  return static_cast<T>(static_cast<std::make_unsigned_t<T>>(val) >> shift);
169,953,049✔
455
}
85,667,615✔
456

457
template <typename T, typename size_type = size_t>
458
constexpr exact_ceil_integral_t<T> lsr(const T val, const size_type shift) {
5,500✔
459
  return static_cast<exact_ceil_integral_t<T>>(static_cast<std::make_unsigned_t<exact_ceil_integral_t<T>>>(val) >> shift);
5,500✔
460
}
2,674✔
461

462
enum class _mask_len {
463
  unknown,
464
  in_range
465
};
466

467
template <std::integral T, _mask_len len_in_range = _mask_len::in_range, typename size_type = size_t>
468
constexpr T _mask(const size_type len) {
42,985,079✔
469
  constexpr std::make_unsigned_t<T> one = std::make_unsigned_t<T>(1);
42,985,079✔
470
  if constexpr (len_in_range != _mask_len::unknown) {
21,412,572✔
471
    return static_cast<T>((one << len) - one);
37,186✔
472
  } else {
21,394,329✔
473
    // The digits_mask is solely here to prevent Undefined Sanitizer
474
    // complaining about shift of len >= digits
475
    // Note: on -O1 the (len & digits_mask) is optimized to simply (len)
476
    constexpr std::make_unsigned_t<T> digits_mask = bitsof<T>() - one;
42,947,893✔
477
    return static_cast<T>((one << (len & digits_mask)) * (len < bitsof<T>()) - one);
42,947,893✔
478
  }
21,394,329✔
479
}
21,412,572✔
480

481
// ------------- IMPLEMENTATION DETAILS: UTILITIES: ASSERTIONS -------------- //
482
// If the range allows multipass iteration, checks if last - first >= 0
483
template <class Iterator>
484
constexpr bool _assert_range_viability(Iterator first, Iterator last) {
979,200✔
485
  using traits_t = std::iterator_traits<Iterator>;
485,521✔
486
  using category_t = typename traits_t::iterator_category;
485,521✔
487
  using multi_t = std::forward_iterator_tag;
485,521✔
488
  constexpr bool is_multipass = std::is_base_of<multi_t, category_t>::value;
979,200✔
489
  const bool is_viable = !is_multipass || std::distance(first, last) >= 0;
1,472,879!
490
  assert(is_viable);
979,200!
491
  return is_viable;
1,472,879✔
492
}
485,521✔
493
// -------------------------------------------------------------------------- //
494

495
// --------- IMPLEMENTATION DETAILS: INSTRUCTIONS: POPULATION COUNT --------- //
496
// Counts the number of bits set to 1 with compiler intrinsics
497
template <class T, class>
498
constexpr T _popcnt(T src) noexcept {
105,216✔
499
  static_assert(binary_digits<T>::value, "");
52,544✔
500
  constexpr T digits = binary_digits<T>::value;
105,216✔
501
  if (digits <= std::numeric_limits<unsigned int>::digits) {
52,544✔
502
    src = __builtin_popcount(static_cast<std::make_unsigned_t<T>>(src));
48,384✔
503
  } else if (digits <= std::numeric_limits<unsigned long int>::digits) {
28,416✔
504
    src = __builtin_popcountl(static_cast<std::make_unsigned_t<T>>(src));
56,832✔
505
  } else if (digits <= std::numeric_limits<unsigned long long int>::digits) {
28,416✔
506
    src = __builtin_popcountll(static_cast<std::make_unsigned_t<T>>(src));
507
  } else {
508
    src = _popcnt(src, std::ignore);
509
  }
510
  return src;
105,216✔
511
}
52,544✔
512

513
// Counts the number of bits set to 1 without compiler intrinsics
514
template <class T, class... X>
515
constexpr T _popcnt(T src, X...) noexcept {
516
  static_assert(binary_digits<T>::value, "");
517
  T dst = T();
518
  for (dst = T(); src; src = lsr(src, 1)) {
519
    dst += src & 1;
520
  }
521
  return dst;
522
}
523
// -------------------------------------------------------------------------- //
524

525
// ------- IMPLEMENTATION DETAILS: INSTRUCTIONS: LEADING ZEROS COUNT -------- //
526
// Counts the number of leading zeros with compiler intrinsics
527
template <class T, class>
528
constexpr T _lzcnt(T src) noexcept {
529
  static_assert(binary_digits<T>::value, "");
530
  constexpr T digits = binary_digits<T>::value;
531
  T dst = T();
532
  if (digits < std::numeric_limits<unsigned int>::digits) {
533
    dst = src ? __builtin_clz(src) - (std::numeric_limits<unsigned int>::digits - digits)
534
              : digits;
535
  } else if (digits == std::numeric_limits<unsigned int>::digits) {
536
    dst = src ? __builtin_clz(src) : digits;
537
  } else if (digits < std::numeric_limits<unsigned long int>::digits) {
538
    dst = src ? __builtin_clzl(src) - (std::numeric_limits<unsigned long int>::digits - digits)
539
              : digits;
540
  } else if (digits == std::numeric_limits<unsigned long int>::digits) {
541
    dst = src ? __builtin_clzl(src) : digits;
542
  } else if (digits < std::numeric_limits<unsigned long long int>::digits) {
543
    dst = src ? __builtin_clzll(src) - (std::numeric_limits<unsigned long long int>::digits - digits)
544
              : digits;
545
  } else if (digits == std::numeric_limits<unsigned long long int>::digits) {
546
    dst = src ? __builtin_clzll(src) : digits;
547
  } else {
548
    dst = _lzcnt(src, std::ignore);
549
  }
550
  return dst;
551
}
552

553
// Counts the number of leading zeros without compiler intrinsics
554
template <class T, class... X>
555
constexpr T _lzcnt(T src, X...) noexcept {
556
  static_assert(binary_digits<T>::value, "");
557
  constexpr T digits = binary_digits<T>::value;
558
  T dst = src != T();
559
  while ((src = lsr(src, 1))) {
560
    ++dst;
561
  }
562
  return digits - dst;
563
}
564
// -------------------------------------------------------------------------- //
565

566
// ------- IMPLEMENTATION DETAILS: INSTRUCTIONS: TRAILING ZEROS COUNT ------- //
567
// Counts the number of trailing zeros with compiler intrinsics
568
template <class T, class>
569
constexpr T _tzcnt(T src) noexcept {
66,558✔
570
  static_assert(binary_digits<T>::value, "");
33,231✔
571
  constexpr T digits = binary_digits<T>::value;
66,558✔
572
  T dst = T();
66,558✔
573
  if (digits <= std::numeric_limits<unsigned int>::digits) {
33,231✔
574
    dst = src ? __builtin_ctz(src) : digits;
32,488!
575
  } else if (digits <= std::numeric_limits<unsigned long int>::digits) {
17,035✔
576
    dst = src ? __builtin_ctzl(src) : digits;
34,070!
577
  } else if (digits <= std::numeric_limits<unsigned long long int>::digits) {
17,035✔
578
    dst = src ? __builtin_ctzll(src) : digits;
×
579
  } else {
580
    dst = _tzcnt(src, std::ignore);
581
  }
582
  return dst;
66,558✔
583
}
33,231✔
584

585
// Counts the number of trailing zeros without compiler intrinsics
586
template <class T, class... X>
587
constexpr T _tzcnt(T src, X...) noexcept {
588
  static_assert(binary_digits<T>::value, "");
589
  constexpr T digits = binary_digits<T>::value;
590
  T dst = digits;
591
  if (src) {
592
    src = lsr((src ^ (src - 1)), 1);
593
    for (dst = T(); src; dst++) {
594
      src = lsr(src, 1);
595
    }
596
  }
597
  return dst;
598
}
599
// -------------------------------------------------------------------------- //
600

601
// ------- IMPLEMENTATION DETAILS: INSTRUCTIONS: BIT FIELD EXTRACTION ------- //
602
// Extacts to lsbs a field of contiguous bits with compiler intrinsics
603
template <class T, class>
604
constexpr T _bextr(T src, T start, T len) noexcept {
605
  static_assert(binary_digits<T>::value, "");
606
  constexpr T digits = binary_digits<T>::value;
607
  T dst = T();
608
  if (digits <= std::numeric_limits<unsigned int>::digits) {
609
    dst = __builtin_ia32_bextr_u32(src, start, len);
610
  } else if (digits <= std::numeric_limits<unsigned long long int>::digits) {
611
    dst = __builtin_ia32_bextr_u64(src, start, len);
612
  } else {
613
    dst = _bextr(src, start, len, std::ignore);
614
  }
615
  return dst;
616
}
617

618
// Extacts to lsbs a field of contiguous bits without compiler intrinsics
619
template <class T, class... X>
620
constexpr T _bextr(T src, T start, T len, X...) noexcept {
15,104✔
621
  static_assert(binary_digits<T>::value, "");
7,616✔
622
  constexpr T digits = binary_digits<T>::value;
15,104✔
623
  constexpr T one = 1;
15,104✔
624
  const T msk = (one << len) * (len < digits) - one;
15,104✔
625
  return (lsr(src, start)) & msk * (start < digits);
15,104✔
626
}
7,616✔
627
// -------------------------------------------------------------------------- //
628

629
#if 0
630
// ------- IMPLEMENTATION DETAILS: INSTRUCTIONS: PARALLEL BIT DEPOSIT ------- //
631
// Deposits bits according to a mask with compiler instrinsics
632
template <class T, class>
633
constexpr T _pdep(T src, T msk) noexcept {
634
  static_assert(binary_digits<T>::value, "");
635
  constexpr T digits = binary_digits<T>::value;
636
  T dst = T();
637
  if (digits <= std::numeric_limits<unsigned int>::digits) {
638
    dst = _pdep_u32(src, msk);
639
  } else if (digits <= std::numeric_limits<unsigned long long int>::digits) {
640
    dst = _pdep_u64(src, msk);
641
  } else {
642
    dst = _pdep(src, msk, std::ignore);
643
  }
644
  return dst;
645
}
646

647
// Deposits bits according to a mask without compiler instrinsics
648
template <class T, class... X>
649
constexpr T _pdep(T src, T msk, X...) noexcept {
650
  static_assert(binary_digits<T>::value, "");
651
  constexpr T digits = binary_digits<T>::value;
652
  T dst = T();
653
  T cnt = T();
654
  while (msk) {
655
    dst = lsr(dst, 1);
656
    if (msk & 1) {
657
      dst |= src << (digits - 1);
658
      src = lsr(src, 1);
659
    }
660
    msk = lsr(msk, 1);
661
    ++cnt;
662
  }
663
  dst = lsr(dst, (digits - cnt) * (cnt > 0));
664
  return dst;
665
}
666
// -------------------------------------------------------------------------- //
667

668
// ------- IMPLEMENTATION DETAILS: INSTRUCTIONS: PARALLEL BIT EXTRACT ------- //
669
// Extracts bits according to a mask with compiler instrinsics
670
template <class T, class>
671
constexpr T _pext(T src, T msk) noexcept {
672
  static_assert(binary_digits<T>::value, "");
673
  constexpr T digits = binary_digits<T>::value;
674
  T dst = T();
675
  if (digits <= std::numeric_limits<unsigned int>::digits) {
676
    dst = _pext_u32(src, msk);
677
  } else if (digits <= std::numeric_limits<unsigned long long int>::digits) {
678
    dst = _pext_u64(src, msk);
679
  } else {
680
    dst = _pext(src, msk, std::ignore);
681
  }
682
  return dst;
683
}
684

685
// Extracts bits according to a mask without compiler instrinsics
686
template <class T, class... X>
687
constexpr T _pext(T src, T msk, X...) noexcept {
688
  static_assert(binary_digits<T>::value, "");
689
  constexpr T digits = binary_digits<T>::value;
690
  T dst = T();
691
  T cnt = T();
692
  while (msk) {
693
    if (msk & 1) {
694
      dst = lsr(dst, 1);
695
      dst |= src << (digits - 1);
696
      ++cnt;
697
    }
698
    src = lsr(src, 1);
699
    msk = lsr(msk, 1);
700
  }
701
  dst = lsr(dst, (digits - cnt) * (cnt > 0));
702
  return dst;
703
}
704
// -------------------------------------------------------------------------- //
705

706
// ------------ IMPLEMENTATION DETAILS: INSTRUCTIONS: BYTE SWAP ------------- //
707
// Reverses the order of the underlying bytes with compiler intrinsics
708
template <class T, class T128>
709
constexpr T _byteswap(T src) noexcept {
710
  static_assert(binary_digits<T>::value, "");
711
  using byte_t = unsigned char;
712
  constexpr T digits = sizeof(T) * std::numeric_limits<byte_t>::digits;
713
  std::uint64_t tmp64 = 0;
714
  std::uint64_t* ptr64 = nullptr;
715
  if (std::is_same<T, T128>::value) {
716
    ptr64 = reinterpret_cast<std::uint64_t*>(&src);
717
    tmp64 = __builtin_bswap64(*ptr64);
718
    *ptr64 = __builtin_bswap64(*(ptr64 + 1));
719
    *(ptr64 + 1) = tmp64;
720
  } else if (digits == std::numeric_limits<std::uint16_t>::digits) {
721
    src = __builtin_bswap16(src);
722
  } else if (digits == std::numeric_limits<std::uint32_t>::digits) {
723
    src = __builtin_bswap32(src);
724
  } else if (digits == std::numeric_limits<std::uint64_t>::digits) {
725
    src = __builtin_bswap64(src);
726
  } else if (digits > std::numeric_limits<byte_t>::digits) {
727
    src = _byteswap(src, std::ignore);
728
  }
729
  return src;
730
}
731

732
// Reverses the order of the underlying bytes without compiler intrinsics
733
template <class T, class... X>
734
constexpr T _byteswap(T src, X...) noexcept {
735
  static_assert(binary_digits<T>::value, "");
736
  using byte_t = unsigned char;
737
  constexpr T half = sizeof(T) / 2;
738
  constexpr T end = sizeof(T) - 1;
739
  unsigned char* bytes = reinterpret_cast<byte_t*>(&src);
740
  unsigned char byte = 0;
741
  for (T i = T(); i < half; ++i) {
742
    byte = bytes[i];
743
    bytes[i] = bytes[end - i];
744
    bytes[end - i] = byte;
745
  }
746
  return src;
747
}
748
// -------------------------------------------------------------------------- //
749
#endif
750

751
// ------------- IMPLEMENTATION DETAILS: INSTRUCTIONS: BIT SWAP ------------- //
752
// Reverses the order of the bits with or without of compiler intrinsics
753
template <class T>
754
constexpr T _bitswap(T src) noexcept {
21,042,880✔
755
  static_assert(binary_digits<T>::value, "");
10,521,728✔
756
  using byte_t = unsigned char;
10,521,728✔
757
  constexpr auto ignore = nullptr;
21,042,880✔
758
  constexpr T digits = binary_digits<T>::value;
21,042,880✔
759
  constexpr unsigned long long int first = 0x80200802ULL;
21,042,880✔
760
  constexpr unsigned long long int second = 0x0884422110ULL;
21,042,880✔
761
  constexpr unsigned long long int third = 0x0101010101ULL;
21,042,880✔
762
  constexpr unsigned long long int fourth = 32;
21,042,880✔
763
  constexpr bool is_size1 = sizeof(T) == 1;
21,042,880✔
764
  constexpr bool is_byte = digits == std::numeric_limits<byte_t>::digits;
21,042,880✔
765
  constexpr bool is_octet = std::numeric_limits<byte_t>::digits == 8;
21,042,880✔
766
  constexpr bool is_pow2 = _popcnt(digits, ignore) == 1;
21,042,880✔
767
  T dst = src;
21,042,880✔
768
  T i = digits - 1;
21,042,880✔
769
  if (is_size1 && is_byte && is_octet) {
10,521,728✔
770
    dst = static_cast<T>(lsr(((static_cast<std::make_unsigned_t<T>>(src) * first) & second) * third, fourth));
5,245,200✔
771
  } else if (is_pow2) {
7,899,296✔
772
    dst = _bitswap<T, digits>(src);
15,797,680✔
773
  } else {
7,899,296✔
774
    for (src = lsr(src, 1); src; src = lsr(src, 1)) {
×
775
      dst <<= 1;
776
      dst |= src & 1;
777
      i--;
778
    }
779
    dst <<= i;
780
  }
781
  return dst;
21,042,880✔
782
}
10,521,728✔
783

784
// Reverses the order of the bits: recursive metafunction
785
template <class T, std::size_t N>
786
constexpr T _bitswap(T src) noexcept {
79,020,032✔
787
  static_assert(binary_digits<T>::value, "");
39,511,840✔
788
  constexpr T cnt = N >> 1;
79,020,032✔
789
  constexpr T msk = _bitswap<T, cnt>();
79,020,032✔
790
  src = ((lsr(src, cnt)) & msk) | ((src << cnt) & ~msk);
79,020,032✔
791
  return cnt > 1 ? _bitswap<T, cnt>(src) : src;
79,020,032✔
792
}
39,511,840✔
793

794
// Reverses the order of the bits: mask for the recursive metafunction
795
template <class T, std::size_t N>
796
constexpr T _bitswap() noexcept {
797
  static_assert(binary_digits<T>::value, "");
798
  constexpr T digits = binary_digits<T>::value;
799
  T cnt = digits;
800
  T msk = ~T();
801
  while (cnt != N) {
802
    cnt = lsr(cnt, 1);
803
    msk ^= (msk << cnt);
804
  }
805
  return msk;
806
}
807
// -------------------------------------------------------------------------- //
808

809
// ------------ IMPLEMENTATION DETAILS: INSTRUCTIONS: BIT BLEND ------------- //
810
// Replaces bits of src0 by the ones of src1 where the mask is true
811
template <class T>
812
constexpr T _bitblend(T src0, T src1, T msk) noexcept {
11,044✔
813
  static_assert(binary_digits<T>::value, "");
5,318✔
814
  return src0 ^ ((src0 ^ src1) & msk);
11,044✔
815
}
5,318✔
816

817
// Replaces len bits of src0 by the ones of src1 starting at start
818
template <class T>
819
constexpr T _bitblend(T src0, T src1, T start, T len) noexcept {
2,038,809✔
820
  static_assert(binary_digits<T>::value, "");
797,485✔
821
  constexpr T digits = binary_digits<T>::value;
2,038,809✔
822
  const T msk = _mask<T, _mask_len::unknown>(len) << start;
2,038,809✔
823
  return src0 ^ ((src0 ^ src1) & msk * (start < digits));
2,038,809✔
824
}
797,485✔
825
// -------------------------------------------------------------------------- //
826

827
// ---------- IMPLEMENTATION DETAILS: INSTRUCTIONS: BIT EXCHANGE ------------ //
828
// Exchanges/swaps bits of src0 by the ones of src1 where the mask is true
829
template <class T>
830
constexpr void _bitexch(T& src0, T& src1, T msk) noexcept {
831
  src0 = src0 ^ static_cast<T>(src1 & msk);
832
  src1 = src1 ^ static_cast<T>(src0 & msk);
833
  src0 = src0 ^ static_cast<T>(src1 & msk);
834
  return;
835
}
836

837
// Replaces len bits of src0 by the ones of src1 starting at start
838
template <class T, class S>
839
constexpr void _bitexch(T& src0, T& src1, S start, S len) noexcept {
7,494✔
840
  static_assert(binary_digits<T>::value, "");
2,370✔
841
  constexpr auto digits = binary_digits<T>::value;
7,494✔
842
  const T msk = (len < digits)
7,494!
843
                    ? _mask<T, _mask_len::unknown>(len) << start
7,470✔
844
                    : -1;  // TODO: What if start > 0 here?
2,370✔
845
  src0 = src0 ^ static_cast<T>(src1 & msk);
7,494✔
846
  src1 = src1 ^ static_cast<T>(src0 & msk);
7,494✔
847
  src0 = src0 ^ static_cast<T>(src1 & msk);
7,494✔
848
  return;
7,494✔
849
}
2,370✔
850

851
// Replaces len bits of src0 by the ones of src1 starting at start0
852
// in src0 and start1 in src1.
853
// len <= digits-max(start0, start1)
854
// clang-format off
855
template <class T, class S>
856
constexpr void _bitexch(T& src0, T& src1, S start0, S start1, S len) noexcept
20,307,140✔
857
{
20,594,587✔
858
    static_assert(binary_digits<T>::value, "");
20,594,587✔
859
    constexpr auto digits = binary_digits<T>::value;
40,901,727✔
860
    const T msk = _mask<T, _mask_len::unknown>(len);
40,901,727✔
861
    if (start0 >= start1) {
40,901,727✔
862
        src0 = src0 ^ (
30,612,099✔
863
                static_cast<T>(src1 << (start0 - start1))
20,455,439✔
864
                &
20,455,439✔
865
                static_cast<T>(msk << start0)
30,612,099✔
866
        );
10,298,779✔
867
        src1 = src1 ^ (
20,455,439✔
868
                static_cast<T>(lsr(src0, (start0 - start1)))
20,455,439✔
869
                &
20,455,439✔
870
                static_cast<T>(msk << start1)
30,612,099✔
871
        );
10,298,779✔
872
        src0 = src0 ^ (
40,768,759✔
873
                static_cast<T>(src1 << (start0 - start1))
20,455,439✔
874
                &
20,455,439✔
875
                static_cast<T>(msk << start0)
30,612,099✔
876
        );
10,298,779✔
877
    } else {
10,298,779✔
878
        src0 = src0 ^ (
20,446,288✔
879
                static_cast<T>(lsr(src1, (start1 - start0)))
20,446,288✔
880
                &
20,446,288✔
881
                static_cast<T>(msk << start0)
30,596,768✔
882
        );
10,295,808✔
883
        src1 = src1 ^ (
30,596,768✔
884
                static_cast<T>(src0 << (start1 - start0))
20,446,288✔
885
                &
20,446,288✔
886
                static_cast<T>(msk << start1)
30,596,768✔
887
        );
10,295,808✔
888
        src0 = src0 ^ (
30,596,768✔
889
                static_cast<T>(lsr(src1, (start1 - start0)))
20,446,288✔
890
                &
20,446,288✔
891
                static_cast<T>(msk << start0)
30,596,768✔
892
        );
10,295,808✔
893
    }
10,295,808✔
894
    return;
40,901,727✔
895
}
20,594,587✔
896
// clang-format on
897
// -------------------------------------------------------------------------- //
898

899
// ----------- IMPLEMENTATION DETAILS: INSTRUCTIONS: BIT COMPARE ------------ //
900
// Compares a subsequence of bits within src0 and src1 and returns 0 if equal
901
template <class T>
902
constexpr T _bitcmp(T src0, T src1, T start0, T start1, T len) noexcept {
903
  static_assert(binary_digits<T>::value, "");
904
  return _bextr(src0, start0, len) == _bextr(src1, start1, len);
905
}
906
// -------------------------------------------------------------------------- //
907

908
// --- IMPLEMENTATION DETAILS: INSTRUCTIONS: DOUBLE PRECISION SHIFT LEFT ---- //
909
// Left shifts dst by cnt bits, filling the lsbs of dst by the msbs of src
910
template <class T>
911
constexpr T _shld(T dst, T src, T cnt) noexcept {
912
  static_assert(binary_digits<T>::value, "");
913
  constexpr T digits = binary_digits<T>::value;
914
  if (cnt < digits) {
915
    dst = (dst << cnt) | (lsr(src, (digits - cnt)));
916
  } else {
917
    dst = (src << (cnt - digits)) * (cnt < digits + digits);
918
  }
919
  return dst;
920
}
921
// -------------------------------------------------------------------------- //
922

923
// --- IMPLEMENTATION DETAILS: INSTRUCTIONS: DOUBLE PRECISION SHIFT RIGHT --- //
924
// Right shifts dst by cnt bits, filling the msbs of dst by the lsbs of src
925
template <class T>
926
constexpr T _shrd(T dst, T src, T cnt) noexcept {
22,279,610✔
927
  static_assert(binary_digits<T>::value, "");
11,838,264✔
928
  constexpr T digits = binary_digits<T>::value;
22,279,610✔
929
  if (cnt < digits) {
22,279,610!
930
    dst = (lsr(dst, cnt)) | (src << (digits - cnt));
22,279,610✔
931
  } else {
11,838,264✔
932
    dst = (lsr(src, (cnt - digits))) * (cnt < digits + digits);
×
933
  }
934
  return dst;
22,279,610✔
935
}
11,838,264✔
936
// -------------------------------------------------------------------------- //
937

938
#if defined(__ADX__)
939
template <bool Add>
940
unsigned char ADDCARRYSUBBORROW32(unsigned char c, uint32_t a, uint32_t b, uint32_t* out) {
941
  return (Add ? _addcarryx_u32(c, a, b, out) : _subborrow_u32(c, a, b, out));
942
}
943
template <bool Add>
944
unsigned char ADDCARRYSUBBORROW64(unsigned char c, uint64_t a, uint64_t b, uint64_t* out) {
945
  static_assert(sizeof(uint64_t) == sizeof(unsigned long long int));
946
  return (Add ? _addcarryx_u64(c, a, b, reinterpret_cast<unsigned long long int*>(out)) : _subborrow_u64(c, a, b, reinterpret_cast<unsigned long long int*>(out)));
947
}
948
#else
949
template <bool Add>
950
unsigned char ADDCARRYSUBBORROW32(unsigned char c, uint32_t a, uint32_t b, uint32_t* out) {
951
  return (Add ? _addcarry_u32(c, a, b, out) : _subborrow_u32(c, a, b, out));
952
}
953
template <bool Add>
954
unsigned char ADDCARRYSUBBORROW64(unsigned char c, uint64_t a, uint64_t b, uint64_t* out) {
955
  static_assert(sizeof(uint64_t) == sizeof(unsigned long long int));
956
  return (Add ? _addcarry_u64(c, a, b, reinterpret_cast<unsigned long long int*>(out)) : _subborrow_u64(c, a, b, reinterpret_cast<unsigned long long int*>(out)));
957
}
958
#endif
959

960
template <bool Add, std::integral U>
961
static inline unsigned char add_carry_sub_borrow(unsigned char c_in, U a, U b, U* out) noexcept {
962
  if constexpr (32 > bitsof<U>()) {
963
    // a       [aaaaaaaa111111111111111111111111111]
964
    // b     + [bbbbbbbb000000000000000000000000000]
965
    // carry +                            [0000000c]
966
    const uint8_t shift = (32 - bitsof<U>());
967
    uint32_t carry_propagation = Add ? ((1 << shift) - 1) : 0;
968
    uint32_t tmp_out;
969
    unsigned char carry = ADDCARRYSUBBORROW32<Add>(
970
        c_in,
971
        (static_cast<uint32_t>(a) << shift) | carry_propagation,
972
        (static_cast<uint32_t>(b) << shift),
973
        &tmp_out);
974
    *out = static_cast<U>(tmp_out >> shift);
975
    return carry;
976
  } else if constexpr (32 == bitsof<U>()) {
977
    return ADDCARRYSUBBORROW32<Add>(c_in, static_cast<uint32_t>(a), static_cast<uint32_t>(b), reinterpret_cast<uint32_t>(out));
978
  } else if constexpr (64 == bitsof<U>()) {
979
    return ADDCARRYSUBBORROW64<Add>(c_in, static_cast<uint64_t>(a), static_cast<uint64_t>(b), reinterpret_cast<uint64_t>(out));
980
  } else if constexpr (0 == (bitsof<U>() % 64)) {
981
    using t64 = std::conditional<std::is_signed_v<U>, int64_t, uint64_t>;
982
    unsigned char carry;
983
    for (int i = 0; i < (bitsof<U>() / 64); i++) {
984
      carry = ADDCARRYSUBBORROW64<Add>(c_in, static_cast<t64>(a >> (i * 64)), static_cast<t64>(b >> (i * 64)), reinterpret_cast<t64>(out) + i);
985
    }
986
    return carry;
987
  } else {
988
    assert(((void)"add carry intrinsics support only support powers of 2 bits", false));
989
  }
990
}
991

992
template <std::integral U>
993
static inline unsigned char add_carry(unsigned char c_in, U a, U b, U* out) noexcept {
994
  return add_carry_sub_borrow<true, U>(c_in, a, b, out);
995
}
996

997
template <std::integral U>
998
static inline unsigned char sub_borrow(unsigned char c_in, U a, U b, U* out) noexcept {
999
  return add_carry_sub_borrow<false, U>(c_in, a, b, out);
1000
}
1001

1002
// -------------------------------------------------------------------------- //
1003

1004
// -------- IMPLEMENTATION DETAILS: INSTRUCTIONS: MULTIWORD MULTIPLY -------- //
1005
// Multiplies src0 and src1 and gets the full result with compiler intrinsics
1006
template <class T, class T128>
1007
constexpr T _mulx(T src0, T src1, T* hi) noexcept
1008
{
1009
    static_assert(binary_digits<T>::value, "");
1010
    using wider_t = ceil_integral<bitsof<T>() + bitsof<T>()>;
1011
    constexpr T digits = binary_digits<T>::value;
1012
    wider_t tmp = 0;
1013
    T128 tmp128 = 0;
1014
    T lo = 0;
1015
    if (digits == std::numeric_limits<std::uint64_t>::digits) {
1016
        tmp128 = static_cast<T128>(src0) * static_cast<T128>(src1);
1017
        *hi = tmp128 >> digits;
1018
        lo = tmp128;
1019
    } else if (digits + digits == binary_digits<wider_t>::value) {
1020
        tmp = static_cast<wider_t>(src0) * static_cast<wider_t>(src1);
1021
        *hi = tmp >> digits;
1022
        lo = tmp;
1023
    } else {
1024
        lo = _mulx(src0, src1, hi, std::ignore);
1025
    }
1026
    return lo;
1027
}
1028

1029
// Multiplies src0 and src1 and gets the full result without compiler intrinsics
1030
template <class T, class... X>
1031
constexpr T _mulx(T src0, T src1, T* hi, X...) noexcept
1032
{
1033
    static_assert(binary_digits<T>::value, "");
1034
    constexpr T digits = binary_digits<T>::value;
1035
    constexpr T offset = digits / 2;
1036
    constexpr T ones = ~static_cast<T>(0);
1037
    const T lsbs0 = src0 & static_cast<T>(lsr(ones, (digits - offset)));
1038
    const T msbs0 = lsr(src0, offset);
1039
    const T lsbs1 = src1 & static_cast<T>(lsr(ones, (digits - offset)));
1040
    const T msbs1 = lsr(src1, offset);
1041
    const T llsbs = lsbs0 * lsbs1;
1042
    const T mlsbs = msbs0 * lsbs1;
1043
    const T lmsbs = lsbs0 * msbs1;
1044
    const T mi = mlsbs + lmsbs;
1045
    const T lo = llsbs + static_cast<T>(mi << offset);
1046
    const T lcarry = lo < llsbs || lo < static_cast<T>(mi << offset);
1047
    const T mcarry = static_cast<T>(mi < mlsbs || mi < lmsbs) << offset;
1048
    *hi = static_cast<T>(lsr(mi, offset)) + msbs0 * msbs1 + mcarry + lcarry;
1049
    return lo;
1050
}
1051
// -------------------------------------------------------------------------- //
1052

1053
template <typename AlgoFunc, typename SrcIt, typename DstIt>
1054
constexpr auto with_bit_iterator_adapter(
7,594✔
1055
    bit_iterator<SrcIt> first,
1056
    bit_iterator<SrcIt> last,
1057
    bit_iterator<DstIt> d_first) {
7,594✔
1058
  using dst_word_type = typename bit_iterator<DstIt>::word_type;
7,594✔
1059
  using src_word_type = typename bit_iterator<SrcIt>::word_type;
7,594✔
1060
  if constexpr (!std::is_same_v<src_word_type, dst_word_type> && bitsof<src_word_type>() != bitsof<dst_word_type>()) {
7,594✔
1061
    if constexpr (bitsof<src_word_type>() > bitsof<dst_word_type>()) {
4,522✔
1062
      bit_iterator<bit_word_pointer_adapter<DstIt, SrcIt>> adapted_first(
9,044✔
1063
          bit_word_pointer_adapter<DstIt, SrcIt>(first.base(), first.position() / bitsof<dst_word_type>()), first.position() % bitsof<dst_word_type>());
6,783✔
1064
      bit_iterator<bit_word_pointer_adapter<DstIt, SrcIt>> adapted_last(
9,044✔
1065
          bit_word_pointer_adapter<DstIt, SrcIt>(last.base(), last.position() / bitsof<dst_word_type>()), last.position() % bitsof<dst_word_type>());
6,783✔
1066
      return AlgoFunc{}(adapted_first, adapted_last, d_first);
6,783✔
1067
    } else {
2,261✔
1068
      bit_iterator<bit_word_pointer_adapter<SrcIt, DstIt>> adapted_d_first(
9,044✔
1069
          bit_word_pointer_adapter<SrcIt, DstIt>(d_first.base(), d_first.position() / bitsof<src_word_type>()), d_first.position() % bitsof<src_word_type>());
6,783✔
1070
      return AlgoFunc{}(first, last, adapted_d_first);
6,783✔
1071
    }
2,261✔
1072
  } else {
4,522✔
1073
    return AlgoFunc{}(first, last, d_first);
9,216✔
1074
  }
3,072✔
1075
}
7,594✔
1076

1077
// ========================================================================== //
1078
}  // namespace bit
1079
#endif // _BIT_DETAILS_HPP_INCLUDED
1080
// ========================================================================== //
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc