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

PeterCDMcLean / BitLib / 15670359432

16 Jun 2025 02:23AM UTC coverage: 54.034% (+0.5%) from 53.519%
15670359432

Pull #12

github

web-flow
Merge c9a3aeb47 into 0f0b787a1
Pull Request #12: Add a bounds type for SystemVerilog style slicing

10319 of 19098 branches covered (54.03%)

Branch coverage included in aggregate %.

94 of 110 new or added lines in 3 files covered. (85.45%)

143 existing lines in 11 files now uncovered.

6061 of 11216 relevant lines covered (54.04%)

7713859.73 hits per line

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

85.88
/include/bitlib/bit-containers/bit_array.hpp
1
// ================================= BIT_ARRAY =================================== //
2
// Project:     The Experimental Bit Algorithms Library
3
// \file        bit_array.hpp
4
// Description: Implementation of bit_array
5
// Creator:     Vincent Reverdy
6
// Contributor: Peter McLean [2025]
7
// License:     BSD 3-Clause License
8
// ========================================================================== //
9
#ifndef _BIT_ARRAY_HPP_INCLUDED
10
#define _BIT_ARRAY_HPP_INCLUDED
11
// ========================================================================== //
12

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

24
// Project sources
25
#include "bitlib/bit-algorithms/bit_algorithm.hpp"
26
#include "bitlib/bit-containers/bit_array_base.hpp"
27
#include "bitlib/bit-containers/bit_bitsof.hpp"
28
#include "bitlib/bit-containers/bit_span.hpp"
29
#include "bitlib/bit-containers/bounds.hpp"
30
#include "bitlib/bit-iterator/bit.hpp"
31
#include "bitlib/bit_concepts.hpp"
32

33
namespace bit {
34
// ========================================================================== //
35

36
namespace detail {
37

38
template <typename value_type, typename word_type, std::size_t N>
UNCOV
39
constexpr size_t Words() { return (N * bitsof<value_type>() + bitsof<word_type>() - 1) / bitsof<word_type>(); }
40

41
template <typename value_type, typename word_type, std::size_t N>
42
using bit_array_d_it = typename std::conditional<std::is_same_v<value_type, bit_value>,
43
                                                 bit_iterator<typename std::array<word_type, Words<value_type, word_type, N>()>::iterator>,
44
                                                 typename std::array<word_type, Words<value_type, word_type, N>()>::iterator>::type;
45

46
template <typename value_type, typename word_type, std::size_t N>
47
using bit_array_d_cit = typename std::conditional<std::is_same_v<value_type, bit_value>,
48
                                                  bit_iterator<typename std::array<word_type, Words<value_type, word_type, N>()>::const_iterator>,
49
                                                  typename std::array<const word_type, Words<value_type, word_type, N>()>::const_iterator>::type;
50
}  // namespace detail
51

52
template <typename T = bit_value,
53
          std::size_t N = std::dynamic_extent,
54
          typename W = std::conditional_t<(N == std::dynamic_extent), std::uintptr_t, ceil_integral<N>>>
55
class bit_array : public bit_array_base<bit_array<T, N, W>, T, N, W, detail::bit_array_d_it<T, W, N>, detail::bit_array_d_cit<T, W, N>> {
56
 public:
57
  using base = bit_array_base<bit_array<T, N, W>, T, N, W, detail::bit_array_d_it<T, W, N>, detail::bit_array_d_cit<T, W, N>>;
58
  using base::end;
59
  using typename base::const_iterator;
60
  using typename base::const_pointer;
61
  using typename base::const_reference;
62
  using typename base::difference_type;
63
  using typename base::iterator;
64
  using typename base::pointer;
65
  using typename base::reference;
66
  using typename base::size_type;
67
  using typename base::value_type;
68
  using typename base::word_type;
69

70
  static constexpr std::size_t bits = N * bitsof<T>();
71

72
 protected:
UNCOV
73
  static constexpr std::size_t Words(std::size_t size_) {
UNCOV
74
    return (size_ * bitsof<value_type>() + bitsof<word_type>() - 1) / bitsof<word_type>();
UNCOV
75
  }
76

77
 private:
78
  std::array<word_type, Words(N)> storage;
79

80
 public:
81
  /*
82
  * Constructors, copies and moves...
83
  */
84
  constexpr bit_array() noexcept : storage{} {}
51✔
85

86
  /*This constructor is purely to simplify some corners of the API*/
87
  constexpr bit_array(size_type size) noexcept : storage{} {
12✔
88
    assert(size == N);
8!
89
  }
8✔
90

91
  constexpr bit_array(value_type bit_val) : storage{} {
2✔
92
    this->fill(bit_val);
2✔
93
  }
2✔
94

95
  template <std::integral U>
96
  constexpr bit_array(const U& integral)
97
    requires(bitsof<U>() <= bits)
98
  {
99
    std::memcpy(&storage[0], &integral, sizeof(integral));
100

101
    bool sign_extend = false;
102
    if constexpr (std::is_signed_v<U>) {
103
      sign_extend = (integral & (1 << (bitsof<U>() - 1))) ? true : false;
104
    }
105
    if (sign_extend) {
106
      for (auto it = begin() + bitsof<U>(); it != end(); ++it) {
107
        *it = bit1;
108
      }
109
    } else {
110
      for (auto it = begin() + bitsof<U>(); it != end(); ++it) {
111
        *it = bit0;
112
      }
113
    }
114
  }
115

116
  constexpr bit_array(const bit_array<T, N, W>& other) noexcept
1✔
117
      : storage(other.storage) {}
2✔
118

119
  constexpr bit_array(const bit_array<T, N, W>&& other) noexcept
1✔
120
      : storage(other.storage) {}
2✔
121

122
  constexpr bit_array(const bit_sized_range auto& other) {
4✔
123
    if (other.size() != this->size()) [[unlikely]] {
4✔
124
      throw std::invalid_argument("other bit_range contains an invalid number of bits for bit_array.");
2✔
125
    }
1✔
126
    ::bit::copy(other.begin(), other.end(), this->begin());
2✔
127
  };
2✔
128

129
  constexpr bit_array(const std::initializer_list<value_type> init)
8✔
130
    requires(!std::is_same_v<value_type, word_type>)
131
  {
8✔
132
    if (init.size() != bitsof(*this)) [[unlikely]] {
16!
133
      throw std::invalid_argument("initialize_list contains an invalid number of bits for bit_array.");
2✔
134
    }
1✔
135
    std::copy(init.begin(), init.end(), this->begin());
14✔
136
  }
14✔
137

138
  constexpr bit_array(const std::initializer_list<bool> init) {
139
    if (init.size() != bitsof(*this)) [[unlikely]] {
140
      throw std::invalid_argument("initialize_list contains an invalid number of bits for bit_array.");
141
    }
142
    std::copy(init.begin(), init.end(), this->begin());
143
  }
144

145
  constexpr bit_array(const std::initializer_list<word_type> init) : storage{} {
146
    // Make sure we handle the case where init.size() != Words
147
    auto it = init.begin();
148
    for (size_type i = 0; i < std::min(Words(N), init.size()); ++i, ++it) {
149
      storage[i] = *it;
150
    }
151
  }
152

153
  constexpr bit_array(const std::string_view s)
2✔
154
    requires(std::is_same_v<value_type, bit_value>)
155
  {
2✔
156
    if (bitsof(*this) != static_cast<size_t>(std::count(s.begin(), s.end(), '0') + std::count(s.begin(), s.end(), '1'))) [[unlikely]] {
4!
157
      throw std::invalid_argument("String contains an invalid number of bits for bit_array.");
2✔
158
    };
1✔
159
    size_type i = 0;
2✔
160
    for (char c : s) {
27!
161
      if (c == '0') {
26!
162
        begin()[i++] = bit0;
10✔
163
      } else if (c == '1') {
16!
164
        begin()[i++] = bit1;
12✔
165
      }
6✔
166
    }
13✔
167
  }
2✔
168

169
  ~bit_array() = default;
170
  /*
171
    * Assignment
172
    */
173
  constexpr bit_array& operator=(const bit_array<T, N, W>& other) = default;
174

175
  constexpr bit_array& operator=(const bit_sized_range auto& other) {
176
    if (other.size() != this->size()) [[unlikely]] {
177
      throw std::invalid_argument("other bit_sized_range contains an invalid number of bits for bit_array.");
178
    }
179
    ::bit::copy(other.begin(), other.end(), this->begin());
180
    return *this;
181
  };
182

183
  constexpr bit_array& operator=(bit_array<T, N, W>&& other) noexcept {
2✔
184
    std::copy(other.storage.begin(), other.storage.end(), storage.begin());
2✔
185
    return *this;
2✔
186
  }
1✔
187

188
  constexpr word_type* data() noexcept {
2✔
189
    return size() ? storage.data() : nullptr;
3!
190
  }
1✔
191

192
  constexpr const word_type* data() const noexcept {
193
    return size() ? storage.data() : nullptr;
194
  }
195

196
  /*
197
    * Iterators
198
    */
199
  constexpr iterator begin() noexcept {
1,273✔
200
    return iterator(storage.begin());
1,273✔
201
  }
879✔
202

203
  constexpr const_iterator begin() const noexcept {
146✔
204
    return const_iterator(storage.begin());
146✔
205
  }
73✔
206

207
  /*
208
    * Capacity
209
    */
210
  constexpr size_type size() const noexcept {
1,334✔
211
    return N;
1,334✔
212
  }
921✔
213

214
  /*
215
    * Operations
216
    */
217
  constexpr void swap(bit_array<T, N, W>& other) noexcept {
2✔
218
    std::swap(this->storage, other.storage);
2✔
219
  }
2✔
220
};
221

222
static_assert(bit_range<bit_array<bit_value, 11>>, "bit_array does not satisfy bit_range concept!");
223
static_assert(bit_sized_range<bit_array<bit_value, 11>>, "bit_array does not satisfy bit_sized_range concept!");
224
#ifdef CONTIGUOUS_RANGE
225
static_assert(bit_contiguous_range<bit_array<11>>, "bit_array does not satisfy bit_contiguous_range concept!");
226
static_assert(bit_contiguous_sized_range<bit_array<11>>, "bit_array does not satisfy bit_contiguous_sized_range concept!");
227
#endif
228

229
#if 0
230
// Class Template Argument Deduction
231
// CTAD guide for the constructor taking a word_type&,
232
// deducing Extent as bitsof<word_type>().
233
template <typename word_type>
234
bit_array(word_type&) -> bit_array<word_type, bitsof<word_type>()>;
235
template <typename word_type>
236
bit_array(word_type*) -> bit_array<word_type, bitsof<word_type>()>;
237

238
// CTAD guide for the constructor taking a word_type* and a size,
239
// which should always be used when Extent is std::dynamic_extent.
240
template <typename word_type>
241
bit_array(word_type&, std::size_t) -> bit_array<word_type, std::dynamic_extent>;
242
template <typename word_type>
243
bit_array(word_type*, std::size_t) -> bit_array<word_type, std::dynamic_extent>;
244
#endif
245

246
}  // namespace bit
247

248
#endif  // _BIT_ARRAY_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