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

PeterCDMcLean / BitLib / 16095803047

06 Jul 2025 05:40AM UTC coverage: 54.449% (+0.3%) from 54.11%
16095803047

push

github

web-flow
Pipecleaning policy and casting issues (#20)

* Pipecleaning policy and casting issues

* Fix policy/conversion issues

* mdspan_accessor was templated incorrectly. bad constructor for bit_reference causes unexpected behavior

* More missing policy templating

* Correct static assert target class

* Disable from_string temporarily as include DAG is misordered with it

* Fix to_integral

* compile-time array_ref extent. word accessor

* Warnings cleanup

* Fix exact integral type

* Squash more warnings

* Prevent some aliasing in the test code which clutters warnings

* Avoid unused variable

---------

Co-authored-by: Peter McLean <peter.cd.mclean@gmail.com>

10164 of 18790 branches covered (54.09%)

Branch coverage included in aggregate %.

532 of 535 new or added lines in 17 files covered. (99.44%)

5 existing lines in 1 file now uncovered.

6237 of 11332 relevant lines covered (55.04%)

7662669.25 hits per line

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

85.31
/include/bitlib/bit-containers/bit_array_base.hpp
1
// ================================= BIT_ARRAY_BASE =================================== //
2
// Project:     The Experimental Bit Algorithms Library
3
// \file        bit_array_base.hpp
4
// Description: Base implementation for bit_array variants
5
// Creator:     Vincent Reverdy
6
// Contributor: Peter McLean [2025]
7
// License:     BSD 3-Clause License
8
// ========================================================================== //
9
#ifndef _BIT_ARRAY_BASE_HPP_INCLUDED
10
#define _BIT_ARRAY_BASE_HPP_INCLUDED
11
// ========================================================================== //
12

13
// ================================ PREAMBLE ================================ //
14
// C++ standard library
15
#include <algorithm>
16
#include <bit>
17
#include <cmath>
18
#include <span>
19
#include <string>
20
#include <type_traits>
21
#include <vector>
22

23
// Project sources
24
#include "bitlib/bit-algorithms/bit_algorithm.hpp"
25
#include "bitlib/bit-containers/bit_bitsof.hpp"
26
#include "bitlib/bit-containers/bit_policy.hpp"
27
#include "bitlib/bit-iterator/bit.hpp"
28

29
namespace bit {
30

31
template <typename T, size_t N, typename W, typename Policy>
32
class array_ref;
33

34
template <typename T,
35
          std::size_t N,
36
          typename W,
37
          typename Policy>
38
class array;
39

40
/**
41
 * @brief Base class template for array implementations
42
 *
43
 * This is a CRTP (Curiously Recurring Template Pattern) base class that provides
44
 * common functionality for array variants.
45
 *
46
 * @tparam Derived The derived class (CRTP pattern)
47
 * @tparam T The value type (typically bit_value)
48
 * @tparam W The word type used for storage
49
 * @tparam N The size of the bit array, or std::dynamic_extent for dynamic size
50
 * @tparam Policy The policy for integral conversion (default is typical)
51
 * @tparam Iterators A struct that provides iterator and const_iterator types
52
 */
53
template <typename Derived, typename T, size_t N, typename W, bool resizable, typename Policy, typename Iterators>
54
class array_base : public detail::container_size_storage<std::size_t, resizable, N> {
55
 protected:
56
  constexpr Derived& derived() noexcept {
4,170✔
57
    return static_cast<Derived&>(*this);
4,170✔
58
  }
2,085✔
59

60
  constexpr const Derived& derived() const noexcept {
242✔
61
    return static_cast<const Derived&>(*this);
242✔
62
  }
121✔
63

64
 public:
65
  using word_type = W;
66
  using value_type = T;
67
  using size_type = std::size_t;
68
  using difference_type = std::ptrdiff_t;
69
  using reference = typename std::conditional<std::is_same_v<T, bit_value>, bit_reference<word_type&>, T&>::type;
70
  using const_reference = typename std::conditional<std::is_same_v<T, bit_value>, const bit_reference<const word_type&>, const T&>::type;
71
  using pointer = typename std::conditional<std::is_same_v<T, bit_value>, bit_pointer<word_type>, T&>::type;
72
  using const_pointer = const pointer;
73
  using iterator = Iterators::iterator;
74
  using const_iterator = Iterators::const_iterator;
75

76
  constexpr array_base() noexcept : detail::container_size_storage<std::size_t, resizable, N>() {}
313✔
77
  constexpr array_base(const size_type& size) noexcept
122✔
78
    requires(N == std::dynamic_extent)
79
      : detail::container_size_storage<std::size_t, resizable, N>(size) {}
244✔
80

81
  // Element access
82
  constexpr reference operator[](size_type pos) {
3,576✔
83
    return derived().begin()[pos];
5,364✔
84
  }
1,788✔
85

86
  constexpr const_reference operator[](size_type pos) const {
87
    return derived().begin()[pos];
88
  }
89

90
  constexpr reference at(size_type pos) {
26✔
91
    if (pos < derived().size()) {
26!
92
      return derived().begin()[pos];
30✔
93
    } else {
10✔
94
      throw std::out_of_range("Position is out of range");
6✔
95
    }
3✔
96
  }
13✔
97

98
  constexpr const_reference at(size_type pos) const {
99
    if (pos < derived().size()) {
100
      return derived().begin()[pos];
101
    } else {
102
      throw std::out_of_range("Position is out of range");
103
    }
104
  }
105

106
  constexpr reference front() {
6✔
107
    return derived().begin()[0];
9✔
108
  }
3✔
109

110
  constexpr const_reference front() const {
111
    return derived().begin()[0];
112
  }
113

114
  constexpr reference back() {
6✔
115
    return derived().begin()[derived().size() - 1];
9✔
116
  }
3✔
117

118
  constexpr const_reference back() const {
119
    return derived().begin()[derived().size() - 1];
120
  }
121

122
  constexpr iterator end() noexcept {
128✔
123
    return derived().begin() + derived().size();
128✔
124
  }
64✔
125

126
  constexpr const_iterator end() const noexcept {
94✔
127
    return const_iterator(derived().begin()) + derived().size();
94✔
128
  }
47✔
129

130
  constexpr const_iterator cbegin() const noexcept {
131
    return const_iterator(derived().begin());
132
  }
133

134
  constexpr const_iterator cend() const noexcept {
135
    return const_iterator(derived().end());
136
  }
137

138
  // Capacity
139
  constexpr bool empty() const noexcept {
8✔
140
    return 0 == derived().size();
8✔
141
  }
4✔
142

143
  constexpr size_type max_size() const noexcept {
2✔
144
    return derived().size();
2✔
145
  }
1✔
146

147
  // String representation
148
  constexpr std::string debug_string() const {
149
    return debug_string(derived().begin(), derived().end());
150
  }
151

152
  constexpr std::string debug_string(const_iterator first, const_iterator last) const {
153
    std::string ret = "";
154
    auto position = 0;
155
    for (auto it = first; it != last; ++it) {
156
      if (position % bitsof<word_type>() == 0 && position != 0) {
157
        ret += " ";
158
      } else if (position % 8 == 0 && position != 0) {
159
        ret += '.';
160
      }
161
      ret += *it == bit1 ? '1' : '0';
162
      ++position;
163
    }
164
    return ret;
165
  }
166

167
  /**
168
   * @brief Slice operations - returns a array_ref
169
   */
170
  constexpr auto operator()(size_type offset, size_type right) const noexcept {
171
    return array_ref<value_type, std::dynamic_extent, const word_type, Policy>(&this->at(offset), right - offset);
172
  }
173

174
  /**
175
   * @brief Slice operations - returns a array_ref
176
   */
177
  constexpr auto operator()(size_type offset, size_type right) noexcept {
16✔
178
    return array_ref<value_type, std::dynamic_extent, word_type, Policy>(&this->at(offset), right - offset);
16✔
179
  }
8✔
180

181
  // Common operations
182
  constexpr void fill(value_type bit_val) noexcept {
76✔
183
    std::fill(derived().begin(), derived().end(), bit_val);
76✔
184
  }
76✔
185

186
  /**
187
   * @brief Explicit conversion to integral types
188
   */
189
  template <std::integral U>
190
  explicit constexpr operator U() const noexcept {
6✔
191
    assert(derived().size() <= bitsof<U>());
6!
192
    U integral;
6✔
193

194
    if constexpr (N == std::dynamic_extent) {
3✔
195
      if (derived().size() > bitsof<U>()) {
4!
196
        Policy::truncation::template to_integral<U, N>(derived(), integral);
×
197
      } else {
2✔
198
        ::bit::copy(derived().begin(), end(), bit_pointer<U>(&integral));
4✔
199
      }
2✔
200
      if (derived().size() < bitsof<U>()) {
4!
NEW
201
        Policy::extension::template to_integral<U, N>(derived(), integral, detail::uninitialized);
×
202
      }
203
    } else {
2✔
204
      if constexpr (N > bitsof<U>()) {
205
        Policy::truncation::template to_integral<U, N>(derived(), integral);
206
      } else {
1✔
207
        ::bit::copy(derived().begin(), end(), bit_pointer<U>(&integral));
2✔
208
      }
1✔
209
      if constexpr (N < bitsof<U>()) {
210
        Policy::extension::template to_integral<U, N>(derived(), integral, detail::uninitialized);
211
      }
212
    }
1✔
213

214
    return integral;
6✔
215
  }
3✔
216

217
  using compatible_bitarray = array<value_type, N, word_type, Policy>;
218

219
  constexpr compatible_bitarray operator~() {
4✔
220
    compatible_bitarray result(derived().size());
6✔
221
    transform(derived().begin(), derived().end(), result.begin(), [](const word_type& bits) -> word_type { return ~bits; });
8✔
222
    return result;
6✔
223
  }
2✔
224

225
  constexpr compatible_bitarray operator|(const bit_sized_range auto& other) const {
2✔
226
    assert(other.size() == derived().size());
2!
227
    compatible_bitarray result(derived().size());
2✔
228
    transform(derived().begin(), derived().end(), other.begin(), result.begin(),
2✔
229
              [](const word_type& a, const word_type& b) -> word_type { return a | b; });
3✔
230
    return result;
3✔
231
  }
1✔
232
  constexpr Derived& operator|=(bit_sized_range auto& other) {
2✔
233
    assert(other.size() == derived().size());
2!
234
    transform(derived().begin(), derived().end(), other.begin(), derived().begin(),
2✔
235
              [](const word_type& a, const word_type& b) -> word_type { return a | b; });
3✔
236
    return derived();
3✔
237
  }
1✔
238
  constexpr compatible_bitarray operator&(const bit_sized_range auto& other) const {
2✔
239
    assert(other.size() == derived().size());
2!
240
    compatible_bitarray result(derived().size());
2✔
241
    transform(derived().begin(), derived().end(), other.begin(), result.begin(),
2✔
242
              [](const word_type& a, const word_type& b) -> word_type { return a & b; });
3✔
243
    return result;
3✔
244
  }
1✔
245
  constexpr Derived& operator&=(bit_sized_range auto& other) {
2✔
246
    assert(other.size() == derived().size());
2!
247
    transform(derived().begin(), derived().end(), other.begin(), derived().begin(),
2✔
248
              [](const word_type& a, const word_type& b) -> word_type { return a & b; });
3✔
249
    return derived();
3✔
250
  }
1✔
251
  constexpr compatible_bitarray operator^(const bit_sized_range auto& other) const {
2✔
252
    assert(other.size() == derived().size());
2!
253
    compatible_bitarray result(derived().size());
2✔
254
    transform(derived().begin(), derived().end(), other.begin(), result.begin(),
2✔
255
              [](const word_type& a, const word_type& b) -> word_type { return a ^ b; });
3✔
256
    return result;
3✔
257
  }
1✔
258
  constexpr Derived& operator^=(bit_sized_range auto& other) {
2✔
259
    assert(other.size() == derived().size());
2!
260
    transform(derived().begin(), derived().end(), other.begin(), derived().begin(),
2✔
261
              [](const word_type& a, const word_type& b) -> word_type { return a ^ b; });
3✔
262
    return derived();
3✔
263
  }
1✔
264

265
 protected:
266
  template <typename U>
267
  constexpr void from_integral(const U& integral) {
80✔
268
    if constexpr (N == std::dynamic_extent) {
269
      if ((derived().size() * bitsof<value_type>()) < bitsof<U>()) {
270
        Policy::truncation::template from_integral<U, N>(derived(), integral);
271
      } else {
272
        bit_pointer<const U> integral_ptr(&integral);
273
        ::bit::copy(integral_ptr, integral_ptr + bitsof<U>(), derived().begin());
274
      }
275
      if (bitsof<U>() < (derived().size() * bitsof<value_type>())) {
276
        Policy::extension::template from_integral<U, N>(derived(), integral, detail::uninitialized);
277
      }
278
    } else {
40✔
279
      if constexpr ((N * bitsof<value_type>()) < bitsof<U>()) {
40✔
280
        Policy::truncation::template from_integral<U, N>(derived(), integral);
40✔
281
      } else {
20✔
282
        bit_pointer<const U> integral_ptr(&integral);
40✔
283
        ::bit::copy(integral_ptr, integral_ptr + bitsof<U>(), derived().begin());
40✔
284
      }
20✔
285
      if constexpr (bitsof<U>() < (N * bitsof<value_type>())) {
286
        Policy::extension::template from_integral<U, N>(derived(), integral, detail::uninitialized);
287
      }
288
    }
40✔
289
  }
80✔
290
};
291

292
constexpr bool operator==(const bit_sized_range auto& lhs, const bit_sized_range auto& rhs) {
56✔
293
  if (lhs.size() != rhs.size()) {
56!
294
    return false;
4✔
295
  }
2✔
296
  return ::bit::equal(lhs.begin(), lhs.end(), rhs.begin());
52✔
297
}
28✔
298

299
}  // namespace bit
300

301
#endif  // _BIT_ARRAY_BASE_HPP_INCLUDED
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

© 2025 Coveralls, Inc