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

PeterCDMcLean / BitLib / 15231126829

24 May 2025 09:26PM UTC coverage: 52.735% (+2.8%) from 49.894%
15231126829

Pull #14

github

web-flow
Merge c21998e55 into d45f839f0
Pull Request #14: Add support for signed word types.

8602 of 16014 branches covered (53.72%)

Branch coverage included in aggregate %.

212 of 260 new or added lines in 12 files covered. (81.54%)

4 existing lines in 1 file now uncovered.

5389 of 10517 relevant lines covered (51.24%)

9195778.6 hits per line

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

85.48
/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(
4,944✔
104
   bit_iterator<RandomAccessIt> first,
105
   bit_iterator<RandomAccessIt> n_first,
106
   bit_iterator<RandomAccessIt> last,
107
   std::random_access_iterator_tag
108
) {
2,448✔
109
    // Types and constants
110
    using word_type = typename bit_iterator<RandomAccessIt>::word_type;
2,448✔
111
    using size_type = typename bit_iterator<RandomAccessIt>::size_type;
2,448✔
112
    using difference_type =
2,448✔
113
        typename bit_iterator<RandomAccessIt>::difference_type;
2,448✔
114
    constexpr difference_type digits = binary_digits<word_type>::value;
7,392✔
115

116
    difference_type k = n_first - first;
7,392✔
117
    difference_type n = last - first;
7,392✔
118

119
    if (k == n - k) {
7,392!
120
        swap_ranges(first, n_first, n_first);
16✔
121
        return n_first;
16✔
122
    }
16✔
123

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

127
    for (;;) {
20,000✔
128
        if (k < n - k) {
24,944✔
129
            if (k <= digits) {
11,408✔
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);
4,224✔
133
                bit_iterator<RandomAccessIt> temp_it = shift_left(p, p + n, k);
4,224✔
134
                write_word<word_type>(temp_word, temp_it, k);
4,224✔
135
                return ret;
4,224✔
136
            }
1,328✔
137
            bit_iterator<RandomAccessIt> q = p + k;
7,184✔
138
            unsigned int full_swaps = (n - k) / k;
7,184✔
139
            size_type remainder = (n - k) - full_swaps*k;
7,184✔
140
            while (full_swaps > 0) {
42,976✔
141
                swap_ranges(p, q, q);
35,792✔
142
                p += k;
35,792✔
143
                q += k;
35,792✔
144
                --full_swaps;
35,792✔
145
            }
12,944✔
146
            swap_ranges(p, p + remainder, q);
7,184✔
147
            p += remainder;
7,184✔
148
            q += remainder;
7,184✔
149
            n %= k;
7,184✔
150
            if (n == 0)
7,184!
151
                return ret;
×
152
            std::swap(n, k);
7,184✔
153
            k = n - k;
7,184✔
154
        } else {
5,632✔
155
            k = n - k;
13,536✔
156
            if (k <= digits) {
13,536✔
157
                word_type temp_word = get_word<word_type>(p + n - k, k);
3,040✔
158
                shift_right(p, p + n, k);
3,040✔
159
                write_word<word_type>(temp_word, p, k);
3,040✔
160
                return ret;
3,040✔
161
            }
1,040✔
162
            bit_iterator<RandomAccessIt> q = p + n;
10,496✔
163
            p = q - k;
10,496✔
164
            unsigned int full_swaps = (n - k) / k;
10,496✔
165
            size_type remainder = (n - k) - full_swaps*k;
10,496✔
166
            while (full_swaps > 0) {
73,888✔
167
                p -= k;
63,392✔
168
                q -= k;
63,392✔
169
                swap_ranges(p, q, q);
63,392✔
170
                --full_swaps;
63,392✔
171
            }
30,800✔
172
            p -= remainder;
10,496✔
173
            q -= remainder;
10,496✔
174
            swap_ranges(p, p + remainder, q);
10,496✔
175
            n %= k;
10,496✔
176
            if (n == 0)
10,496!
177
                return ret;
112✔
178
            std::swap(n, k);
10,384✔
179
        }
4,528✔
180
    }
9,728✔
181
}
2,432✔
182

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

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

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

208
    // Within the same word
209
    if (std::next(first.base(), is_last_aligned) == last.base()) {
45,600✔
210
        if (is_first_aligned && is_last_aligned) {
5,840!
NEW
211
          *first.base() =
×
NEW
212
              (lsr(*first.base(), n_first.position())) |
×
NEW
213
              static_cast<word_type>(
×
NEW
214
                  *first.base() << (digits - n_first.position()));
×
NEW
215
          return std::next(first, digits - n_first.position());
×
216
        } else {
2,960✔
217
            size_type last_pos = is_last_aligned ? digits : last.position();
5,840!
218
            size_type k = n_first.position() - first.position();
5,840✔
219
            size_type p = last_pos - n_first.position();
5,840✔
220
            size_type d = last_pos - first.position();
5,840✔
221

222
            word_type mask = _mask<word_type>(d) << first.position();
5,840✔
223
            word_type rotated = *first.base() & mask;
5,840✔
224
            rotated = static_cast<word_type>(lsr(rotated, k)) | static_cast<word_type>(rotated << p);
5,840✔
225
            *first.base() = _bitblend<word_type>(
6,832✔
226
                *first.base(),
8,720✔
227
                rotated,
2,960✔
228
                first.position(),
4,848✔
229
                d
2,960✔
230
            );
2,960✔
231
            return std::next(first, p);
8,720✔
232
        }
2,960✔
233
    }
2,960✔
234

235
    // Single word subcases
236
    if (is_within<digits>(first, n_first)) {
24,656!
237
        size_type k = distance(first, n_first);
12,992✔
238
        word_type temp = get_word<word_type>(first, k);
12,992✔
239
        bit_iterator<ForwardIt> new_last = shift_left(first, last, k);
12,992✔
240
        write_word<word_type>(temp, new_last, static_cast<word_type>(k));
12,992✔
241
        return new_last;
12,992✔
242
    } else if (is_within<digits>(n_first, last)) {
13,248!
243
        size_type p = distance(n_first, last);
4,272✔
244
        word_type temp = get_word<word_type>(n_first, p);
4,272✔
245
        auto new_last = shift_right(first, last, p);
4,272✔
246
        write_word(temp, first, static_cast<word_type>(p));
4,272✔
247
        return new_last;
4,272✔
248
    }
2,976✔
249
    return _rotate_via_raw(
17,280✔
250
            first,
2,448✔
251
            n_first,
2,448✔
252
            last,
2,448✔
253
            typename std::iterator_traits<ForwardIt>::iterator_category()
2,448✔
254
    );
22,224✔
255
}
12,432✔
256

257

258
// ========================================================================== //
259
} // namespace bit
260
#endif // _ROTATE_HPP_INCLUDED
261
// ========================================================================== //
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