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

PeterCDMcLean / BitLib / 14815058283

03 May 2025 10:15PM UTC coverage: 97.623% (-0.5%) from 98.083%
14815058283

push

github

PeterCDMcLean
Add codecov yml to filter libpopcnt.h

1273 of 1304 relevant lines covered (97.62%)

16928314.29 hits per line

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

93.75
/include/bitlib/bit-algorithms/rotate.hpp
1
// ================================= ROTATE ================================= //
2
// Project:         The Experimental Bit Algorithms Library
3
// Name:            rotate.hpp
4
// Description:     bit_iterator overloads for std::rotate
5
// Contributor(s):  Bryce Kille [2019]
6
// License:         BSD 3-Clause License
7
// ========================================================================== //
8
#ifndef _ROTATE_HPP_INCLUDED
9
#define _ROTATE_HPP_INCLUDED
10
// ========================================================================== //
11

12

13

14
// ============================== PREAMBLE ================================== //
15
// C++ standard library
16
#include <iostream>
17
// Project sources
18
#include "bit_algorithm.hpp"
19
// Third-party libraries
20
// Miscellaneous
21
namespace bit {
22
// ========================================================================== //
23

24
// Rotates a range by copying [first...n_first) to the stack, then shifting
25
// the range to the left and appending the copied section to the end.
26
//
27
// Note: distance(first, n_first) <= 3*digits
28
template <class ForwardIt, int BufferSize>
29
bit_iterator<ForwardIt> _rotate_via_copy_begin(
30
   bit_iterator<ForwardIt> first,
31
   bit_iterator<ForwardIt> n_first,
32
   bit_iterator<ForwardIt> last
33
) {
34
    // Types and constants
35
    using word_type = typename bit_iterator<ForwardIt>::word_type;
36
    using size_type = typename bit_iterator<ForwardIt>::size_type;
37
    constexpr size_type digits = binary_digits<word_type>::value;
38

39
    size_type k = distance(first, n_first);
40
    assert(k <= BufferSize*digits);
41
    word_type copy_arr[BufferSize];
42
    copy_arr[0] = *first.base();
43
    ForwardIt it = ++first.base();
44
    short unsigned int pos = 1;
45
    short int bits_left_to_copy = k - (digits - first.position());
46
    while (bits_left_to_copy > 0) {
47
        copy_arr[pos++] = *it++;
48
        bits_left_to_copy -= digits;
49
    }
50
    bit_iterator<ForwardIt> ret = shift_left(first, last, k);
51
    copy(
52
        bit_iterator<word_type*>(copy_arr, first.position()),
53
        bit_iterator<word_type*>(
54
                copy_arr,
55
                first.position()
56
        ) + k,
57
        ret
58
    );
59
    return ret;
60
}
61

62
// Rotates a range by copying [n_first, last) to the stack, then shifting
63
// the range to the right and prepending the copied section to the beginning.
64
//
65
// Note: distance(n_first, last) <= 3*digits
66
template <class ForwardIt, int BufferSize>
67
bit_iterator<ForwardIt> _rotate_via_copy_end(
68
   bit_iterator<ForwardIt> first,
69
   bit_iterator<ForwardIt> n_first,
70
   bit_iterator<ForwardIt> last
71
) {
72
    // Types and constants
73
    using word_type = typename bit_iterator<ForwardIt>::word_type;
74
    using size_type = typename bit_iterator<ForwardIt>::size_type;
75
    constexpr size_type digits = binary_digits<word_type>::value;
76

77
    size_type k = distance(n_first, last);
78
    assert(k <= BufferSize*digits);
79
    word_type copy_arr[BufferSize];
80
    copy_arr[0] = *n_first.base();
81
    ForwardIt it = ++n_first.base();
82
    short unsigned int pos = 1;
83
    short int bits_left_to_copy = k - (digits - n_first.position());
84
    while (bits_left_to_copy > 0) {
85
        copy_arr[pos++] = *it++;
86
        bits_left_to_copy -= digits;
87
    }
88
    bit_iterator<ForwardIt> ret = shift_right(first, last, k);
89
    copy(
90
        bit_iterator<word_type*>(copy_arr, n_first.position()),
91
        bit_iterator<word_type*>(
92
                copy_arr,
93
                n_first.position()
94
        ) + k,
95
        first
96
    );
97
    return ret;
98
}
99

100
// Rotates a range using random-access iterators. Algorithm logic from the GCC
101
// implementation
102
template <class RandomAccessIt>
103
bit_iterator<RandomAccessIt> _rotate_via_raw(
1,533✔
104
   bit_iterator<RandomAccessIt> first,
105
   bit_iterator<RandomAccessIt> n_first,
106
   bit_iterator<RandomAccessIt> last,
107
   std::random_access_iterator_tag
108
) {
109
    // Types and constants
110
    using word_type = typename bit_iterator<RandomAccessIt>::word_type;
111
    using size_type = typename bit_iterator<RandomAccessIt>::size_type;
112
    using difference_type =
113
        typename bit_iterator<RandomAccessIt>::difference_type;
114
    constexpr difference_type digits = binary_digits<word_type>::value;
1,533✔
115

116
    difference_type k = n_first - first;
1,533✔
117
    difference_type n = last - first;
1,533✔
118

119
    if (k == n - k) {
1,533✔
120
        swap_ranges(first, n_first, n_first);
14✔
121
        return n_first;
14✔
122
    }
123

124
    bit_iterator<RandomAccessIt> p = first;
1,519✔
125
    bit_iterator<RandomAccessIt> ret = first + (last - n_first);
1,519✔
126

127
    for (;;) {
4,049✔
128
        if (k < n - k) {
5,568✔
129
            if (k <= digits) {
2,768✔
130
                // BENCHMARK NOTE: may be better to do k <= 3*digits and use
131
                // the _rotate_via_copy method.
132
                word_type temp_word = get_word<word_type>(p, k);
719✔
133
                bit_iterator<RandomAccessIt> temp_it = shift_left(p, p + n, k);
719✔
134
                write_word<word_type>(temp_word, temp_it, k);
719✔
135
                return ret;
719✔
136
            }
137
            bit_iterator<RandomAccessIt> q = p + k;
2,049✔
138
            unsigned int full_swaps = (n - k) / k;
2,049✔
139
            size_type remainder = (n - k) - full_swaps*k;
2,049✔
140
            while (full_swaps > 0) {
15,448✔
141
                swap_ranges(p, q, q);
13,399✔
142
                p += k;
13,399✔
143
                q += k;
13,399✔
144
                --full_swaps;
13,399✔
145
            }
146
            swap_ranges(p, p + remainder, q);
2,049✔
147
            p += remainder;
2,049✔
148
            q += remainder;
2,049✔
149
            n %= k;
2,049✔
150
            if (n == 0)
2,049✔
151
                return ret;
11✔
152
            std::swap(n, k);
2,038✔
153
            k = n - k;
2,038✔
154
        } else {
155
            k = n - k;
2,800✔
156
            if (k <= digits) {
2,800✔
157
                word_type temp_word = get_word<word_type>(p + n - k, k);
770✔
158
                shift_right(p, p + n, k);
770✔
159
                write_word<word_type>(temp_word, p, k);
770✔
160
                return ret;
770✔
161
            }
162
            bit_iterator<RandomAccessIt> q = p + n;
2,030✔
163
            p = q - k;
2,030✔
164
            unsigned int full_swaps = (n - k) / k;
2,030✔
165
            size_type remainder = (n - k) - full_swaps*k;
2,030✔
166
            while (full_swaps > 0) {
17,262✔
167
                p -= k;
15,232✔
168
                q -= k;
15,232✔
169
                swap_ranges(p, q, q);
15,232✔
170
                --full_swaps;
15,232✔
171
            }
172
            p -= remainder;
2,030✔
173
            q -= remainder;
2,030✔
174
            swap_ranges(p, p + remainder, q);
2,030✔
175
            n %= k;
2,030✔
176
            if (n == 0)
2,030✔
177
                return ret;
19✔
178
            std::swap(n, k);
2,011✔
179
        }
180
    }
181
}
182

183
// Main function for implementing the bit overload of std::rotate.
184
template <class ForwardIt>
185
bit_iterator<ForwardIt> rotate(
8,256✔
186
   bit_iterator<ForwardIt> first,
187
   bit_iterator<ForwardIt> n_first,
188
   bit_iterator<ForwardIt> last
189
) {
190
    // Assertions
191
    _assert_range_viability(first, n_first);
8,256✔
192
    _assert_range_viability(n_first, last);
8,256✔
193
    _assert_range_viability(first, last);
8,256✔
194
    //if (first == n_first) return n_first;
195
    if (first == n_first) return last;
8,256✔
196

197
    // Types and constants
198
    using word_type = typename bit_iterator<ForwardIt>::word_type;
199
    using size_type = typename bit_iterator<ForwardIt>::size_type;
200
    using difference_type =
201
        typename bit_iterator<ForwardIt>::difference_type;
202
    constexpr difference_type digits = binary_digits<word_type>::value;
7,693✔
203

204
    // Initialization
205
    const bool is_first_aligned = first.position() == 0;
7,693✔
206
    const bool is_last_aligned = last.position() == 0;
7,693✔
207

208
    // Within the same word
209
    if (std::next(first.base(), is_last_aligned) == last.base()) {
15,386✔
210
        if (is_first_aligned && is_last_aligned) {
1,542✔
211
            *first.base() =
×
212
                (*first.base() >> n_first.position())
×
213
                |
×
214
                static_cast<word_type>(
×
215
                        *first.base() << (digits - n_first.position())
×
216
            );
217
            return std::next(first, digits - n_first.position());
×
218
        } else {
219
            size_type last_pos = is_last_aligned ? digits : last.position();
1,542✔
220
            size_type k = n_first.position() - first.position();
1,542✔
221
            size_type p = last_pos - n_first.position();
1,542✔
222
            size_type d = last_pos - first.position();
1,542✔
223

224
            word_type mask = ((1ULL << d) - 1) << first.position();
1,542✔
225
            word_type rotated = *first.base() & mask;
1,542✔
226
            rotated = static_cast<word_type>(rotated >> k)
1,542✔
227
                | static_cast<word_type>(rotated << p);
1,542✔
228
            *first.base() = _bitblend<word_type>(
2,446✔
229
                *first.base(),
3,084✔
230
                rotated,
231
                first.position(),
638✔
232
                d
233
            );
234
            return std::next(first, p);
3,084✔
235
        }
236
    }
237

238
    // Single word subcases
239
    if (is_within<digits>(first, n_first)) {
6,151✔
240
        size_type k = distance(first, n_first);
2,923✔
241
        word_type temp = get_word<word_type>(first, k);
2,923✔
242
        bit_iterator<ForwardIt> new_last = shift_left(first, last, k);
2,923✔
243
        write_word<word_type>(temp, new_last, static_cast<word_type>(k));
2,923✔
244
        return new_last;
2,923✔
245
    } else if (is_within<digits>(n_first, last)) {
3,228✔
246
        size_type p = distance(n_first, last);
1,695✔
247
        word_type temp = get_word<word_type>(n_first, p);
1,695✔
248
        auto new_last = shift_right(first, last, p);
1,695✔
249
        write_word(temp, first, static_cast<word_type>(p));
1,695✔
250
        return new_last;
1,695✔
251
    }
252
    return _rotate_via_raw(
1,533✔
253
            first,
254
            n_first,
255
            last,
256
            typename std::iterator_traits<ForwardIt>::iterator_category()
257
    );
1,533✔
258
}
259

260

261
// ========================================================================== //
262
} // namespace bit
263
#endif // _ROTATE_HPP_INCLUDED
264
// ========================================================================== //
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