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

PeterCDMcLean / BitLib / 16781103655

06 Aug 2025 03:17PM UTC coverage: 74.757%. Remained the same
16781103655

push

github

web-flow
Use upload / download action instead of cache (#28)

* Use upload / download action instead of cache

* Try without single quotes

* Rerun base_ref build if possible

3451 of 5352 branches covered (64.48%)

Branch coverage included in aggregate %.

2555 of 2682 relevant lines covered (95.26%)

29850565.99 hits per line

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

85.38
/include/bitlib/bit-containers/bit_array_dynamic_extent.hpp
1
// ================================= BIT_ARRAY =================================== //
2
// Project:     The Experimental Bit Algorithms Library
3
// \file        bit_array_dynamic_extent.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_DYNAMIC_EXTENT_HPP_INCLUDED
10
#define _BIT_ARRAY_DYNAMIC_EXTENT_HPP_INCLUDED
11

12
#include <algorithm>
13
#include <cstddef>
14
#include <initializer_list>
15
#include <memory>
16
#include <new>
17
#include <span>  // std::dynamic_extent
18
#include <stdexcept>
19

20
#include "bitlib/bit-algorithms/bit_algorithm.hpp"
21
#include "bitlib/bit-containers/bit_array.hpp"
22
#include "bitlib/bit-containers/bit_array_base.hpp"
23
#include "bitlib/bit-containers/bit_bitsof.hpp"
24
#include "bitlib/bit-containers/bit_policy.hpp"
25
#include "bitlib/bit-iterator/bit.hpp"
26
#include "bitlib/bit_concepts.hpp"
27

28
namespace bit {
29
namespace detail {
30

31
template <typename value_type, typename word_type>
32
struct array_dextent_iterator_types {
33
  using iterator = typename std::conditional<std::is_same_v<value_type, bit_value>,
34
                                             bit_iterator<word_type*>,
35
                                             word_type*>::type;
36
  using const_iterator = typename std::conditional<std::is_same_v<value_type, bit_value>,
37
                                                   bit_iterator<const word_type*>,
38
                                                   const word_type*>::type;
39
};
40
}  // namespace detail
41
template <typename T, typename W, typename Policy>
42
class array<T, std::dynamic_extent, W, Policy>
43
    : public array_base<array<T, std::dynamic_extent, W, Policy>, T, std::dynamic_extent, W, false, Policy, detail::array_dextent_iterator_types<T, W>> {
44
 public:
45
  using base = array_base<array<T, std::dynamic_extent, W, Policy>, T, std::dynamic_extent, W, false, Policy, detail::array_dextent_iterator_types<T, W>>;
46
  using base::end;
47
  using base::size;
48
  using typename base::const_iterator;
49
  using typename base::const_pointer;
50
  using typename base::const_reference;
51
  using typename base::difference_type;
52
  using typename base::iterator;
53
  using typename base::pointer;
54
  using typename base::reference;
55
  using typename base::size_type;
56
  using typename base::value_type;
57
  using typename base::word_type;
58
  using Allocator = typename Policy::allocator;
59

60
 private:
61
  using word_type_ptr = word_type*;
62
#if defined(__clang__) || defined(__GNUC__)
63
#pragma GCC diagnostic push
64
#pragma GCC diagnostic ignored "-Wsizeof-pointer-div"
65
#endif
66
  static const size_type FixedWords = sizeof(word_type_ptr) / sizeof(word_type);
67
#if defined(__clang__) || defined(__GNUC__)
68
#pragma GCC diagnostic pop
69
#endif
70
  static const size_type FixedBits = FixedWords * bitsof<word_type>();
71

72
  struct Storage {
73
    union {
74
      word_type_ptr pointer;
75
      word_type fixed[FixedWords];
76
    };
77
    Allocator m_allocator;
78

79
    Storage(size_type words, const Allocator& allocator, detail::uninitialized_t) : m_allocator(allocator) {
117✔
80
      if (words > FixedWords) {
78!
81
        new (&pointer) word_type_ptr(m_allocator.allocate(words));
×
82
      }
83
    }
78✔
84

85
    Storage(size_type words, const Allocator& allocator = Allocator()) : m_allocator(allocator) {
39✔
86
      if (words > FixedWords) {
26✔
87
        new (&pointer) word_type_ptr(m_allocator.allocate(words));
18✔
88
        for (size_type i = 0; i < words; ++i) {
135,403,572✔
89
          new (pointer + i) word_type();
135,403,560✔
90
        }
67,701,780✔
91
      } else {
7✔
92
        for (size_type i = 0; i < words; ++i) {
28✔
93
          new (&fixed[i]) word_type();
14✔
94
        }
7✔
95
      }
7✔
96
    }
26✔
97

98
    Storage(size_type words, Storage&& other) {
12✔
99
      if (words > FixedWords) {
8!
100
        new (&pointer) word_type_ptr(std::move(other.pointer));
×
101
        other.pointer = nullptr;  // Prevent double deletion
×
102
      } else {
4✔
103
        for (size_type i = 0; i < words; ++i) {
16✔
104
          new (&fixed[i]) word_type(std::move(other.fixed[i]));
8✔
105
        }
4✔
106
      }
4✔
107
    }
8✔
108

109
    Storage(size_type words, const Storage& other, const Allocator& allocator = Allocator())
4✔
110
        : m_allocator(allocator) {
4✔
111
      if (words > FixedWords) {
4!
112
        new (&pointer) word_type_ptr(m_allocator.allocate(words));
×
113
        for (size_t i = 0; i < words; ++i) {
×
114
          new (pointer + i) word_type(other.pointer[i]);
×
115
        }
116
        std::copy_n(other.pointer, words, pointer);
×
117
      } else {
2✔
118
        for (size_type i = 0; i < words; ++i) {
8✔
119
          new (&fixed[i]) word_type(other.fixed[i]);
4✔
120
        }
2✔
121
      }
2✔
122
    }
4✔
123
    template <typename U>
124
    Storage(size_type words, const U& val, const Allocator& allocator = Allocator())
125
        : m_allocator(allocator) {
126
      if (words > FixedWords) {
127
        new (&pointer) word_type_ptr(m_allocator.allocate(words));
128
        for (size_t i = 0; i < words; ++i) {
129
          new (pointer + i) word_type(val);
130
        }
131
      } else {
132
        for (size_type i = 0; i < words; ++i) {
133
          new (&fixed[i]) word_type(val);
134
        }
135
      }
136
    }
137
    Storage() = delete;
138
    ~Storage() {};
232✔
139
  } storage;
140

141
  static constexpr size_type Words(size_type N) {
354✔
142
    return (N * bitsof<value_type>() + bitsof<word_type>() - 1) / bitsof<word_type>();
354✔
143
  };
177✔
144

145
 public:
146
  ~array() {
116✔
147
    if (size() > FixedBits) {
116!
148
      storage.m_allocator.deallocate(storage.pointer, Words(size()));
12✔
149
    } else if constexpr (!std::is_fundamental_v<T>) {
52✔
150
      for (size_type i = 0; i < Words(size()); ++i) {
210✔
151
        // W is 'word_type', but MSVC is unhappy with using an alias
152
        storage.fixed[i].~W();
106✔
153
      }
53✔
154
    }
52✔
155
  }
116✔
156

157
  /*
158
  * Constructors, copies and moves...
159
  */
160
  array() = delete;
161

162
  constexpr array(const size_type extent, const Allocator& allocator = Allocator())
13✔
163
      : base(extent), storage(Words(extent), allocator) {
26✔
164
  }
26✔
165

166
  constexpr array(detail::uninitialized_t, const size_type extent, const Allocator& allocator = Allocator())
1✔
167
      : base(extent), storage(Words(extent), allocator, detail::uninitialized) {
2✔
168
  }
2✔
169

170
  template <std::integral U>
171
  constexpr array(const size_type extent, const U& integral, const Allocator& allocator = Allocator())
172
      : base(extent), storage(Words(extent), allocator, detail::uninitialized) {
173
    this->from_integral(integral);
174
  }
175

176
  constexpr array(const size_type extent, const word_type val, const Allocator& allocator = Allocator())
177
      : base(extent), storage(Words(extent), val, allocator) {
178
  }
179

180
  constexpr array(const size_type extent, const value_type bit_val, const Allocator& allocator = Allocator())
23✔
181
    requires(!std::is_same<value_type, word_type>::value)
182
      : base(extent), storage(Words(extent), allocator, detail::uninitialized) {
46✔
183
    this->fill(bit_val);
46✔
184
  }
46✔
185

186
  constexpr array(const array<T, std::dynamic_extent, W, Policy>& other)
2✔
187
      : base(other.size()), storage(Words(size()), other.storage) {
8✔
188
  }
4✔
189

190
  constexpr array(const array<T, std::dynamic_extent, W, Policy>& other, const Allocator& allocator)
191
      : base(other.size()), storage(Words(size()), other.storage, allocator) {
192
  }
193

194
  constexpr array(const bit_sized_range auto& other, const Allocator& allocator = Allocator())
195
      : base(other.size()), storage(Words(size()), allocator, detail::uninitialized) {
196
    ::bit::copy(other.begin(), other.end(), this->begin());
197
  }
198

199
  constexpr array(array<T, std::dynamic_extent, W, Policy>&& other)
4✔
200
      : base(other.size()), storage(Words(size()), std::move(other.storage)) {
8✔
201
  }
8✔
202

203
  constexpr array(array<T, std::dynamic_extent, W, Policy>&& other, const Allocator& allocator)
204
      : base(other.size()), storage(Words(size()), std::move(other.storage), allocator) {
205
  }
206

207
  constexpr array(const std::initializer_list<value_type> init, const Allocator& allocator = Allocator())
12✔
208
    requires(!std::is_same_v<value_type, word_type>)
209
      : base(init.size()), storage(Words(size()), allocator, detail::uninitialized) {
24✔
210
    std::copy(init.begin(), init.end(), this->begin());
24✔
211
  }
24✔
212

213
#if 0
214
  No known conversion from bool to bit_value
215
  bit_value has explicit constructor from bool to bit_value so this doesnt work
216
  constexpr array<std::dynamic_extent, W, Policy>::array(const std::initializer_list<bool> init)
217
      : storage(std::make_unique<word_type[]>(Words(init.size()))),
218
        base(init.size()) {
219
    std::copy(init.begin(), init.end(), this->begin());
220
  }
221
#endif
222

223
  template <typename U>
224
  constexpr array(const std::initializer_list<U> init, const Allocator& allocator = Allocator())
1✔
225
      : base(bitsof<U>() * init.size()), storage(Words(size()), allocator, detail::uninitialized) {
2✔
226
    std::copy(init.begin(), init.end(), data());
2✔
227
  }
2✔
228

229
  constexpr array(const std::string_view s, const Allocator& allocator = Allocator())
2✔
230
    requires(std::is_same_v<value_type, bit_value>)
231
      : base(std::count(s.begin(), s.end(), '0') + std::count(s.begin(), s.end(), '1')), storage(Words(size()), allocator, detail::uninitialized) {
4✔
232
    size_type i = 0;
4✔
233
    for (char c : s) {
32✔
234
      if (c == '0') {
30✔
235
        begin()[i++] = bit0;
14✔
236
      } else if (c == '1') {
16!
237
        begin()[i++] = bit1;
16✔
238
      }
8✔
239
    }
15✔
240
  }
4✔
241

242
  /*
243
   * Assignment
244
   */
245
  constexpr array<T, std::dynamic_extent, W, Policy>& operator=(const array<T, std::dynamic_extent, W, Policy>& other) {
6✔
246
    if (nullptr == data() || size() != other.size()) {
6!
247
      throw std::invalid_argument("Cannot reassign array<std::dynamic_extent,V,W,Policy> extent");
4✔
248
    }
2✔
249
    if (this == &other) [[unlikely]] {
2!
250
      return *this;
×
251
    }
252
    std::copy(other.begin(), other.end(), this->begin());
2✔
253
    return *this;
2✔
254
  }
1✔
255

256
  constexpr array<T, std::dynamic_extent, W, Policy>& operator=(const bit_sized_range auto& other) {
4✔
257
    if (other.size() != this->size()) [[unlikely]] {
4✔
258
      throw std::invalid_argument("other bit_range contains an invalid number of bits for array.");
2✔
259
    }
1✔
260
    ::bit::copy(other.begin(), other.end(), this->begin());
2✔
261
    return *this;
3✔
262
  };
2✔
263

264
  constexpr array<T, std::dynamic_extent, W, Policy>& operator=(array<T, std::dynamic_extent, W, Policy>&& other) {
8✔
265
    if (nullptr == data() || size() != other.size()) {
8!
266
      throw std::invalid_argument("Cannot reassign array<std::dynamic_extent,V,W,Policy> extent");
2✔
267
    }
1✔
268
    array<T, std::dynamic_extent, W, Policy> temp(std::move(other));
6✔
269
    swap(temp);
6✔
270
    return *this;
9✔
271
  }
7✔
272

273
  /*
274
   * Element Access
275
   */
276
  constexpr word_type* data() noexcept {
36✔
277
    if (size() > FixedBits) {
36!
278
      return storage.pointer;
×
279
    } else {
18✔
280
      return storage.fixed;
36✔
281
    }
18✔
282
  }
18✔
283

284
  constexpr const word_type* data() const noexcept {
285
    if (size() > FixedBits) {
286
      return storage.pointer;
287
    } else {
288
      return storage.fixed;
289
    }
290
  }
291

292
  /*
293
   * Iterators
294
   */
295
  constexpr iterator begin() noexcept {
2,552✔
296
    if (size() > FixedBits) {
2,552!
297
      return iterator(storage.pointer);
1,686✔
298
    } else {
843✔
299
      return iterator(storage.fixed);
866✔
300
    }
433✔
301
  }
1,276✔
302

303
  constexpr const_iterator begin() const noexcept {
48✔
304
    if (size() > FixedBits) {
48!
305
      return const_iterator(storage.pointer);
×
306
    } else {
24✔
307
      return const_iterator(storage.fixed);
48✔
308
    }
24✔
309
  }
24✔
310

311
  /*
312
   * Operations
313
   */
314
  constexpr void swap(array<T, std::dynamic_extent, W, Policy>& other) noexcept {
8✔
315
    assert(size() == other.size());
8!
316
    if (size() > FixedBits) {
8!
317
      std::swap(this->storage.pointer, other.storage.pointer);
×
318
    } else {
4✔
319
      for (size_type i = 0; i < Words(size()); ++i) {
16✔
320
        std::swap(this->storage.fixed[i], other.storage.fixed[i]);
8✔
321
      }
4✔
322
    }
4✔
323
  }
8✔
324
};
325

326
static_assert(bit_range<bit_array<>>, "array<> does not satisfy bit_contiguous_range concept!");
327
static_assert(bit_sized_range<bit_array<>>, "array<> does not satisfy bit_contiguous_sized_range concept!");
328
#ifdef CONTIGUOUS_RANGE
329
static_assert(bit_contiguous_range<array<>>, "array<> does not satisfy bit_contiguous_range concept!");
330
static_assert(bit_contiguous_sized_range<array<>>, "array<> does not satisfy bit_contiguous_sized_range concept!");
331
#endif
332

333
// ========================================================================== //
334
}  // namespace bit
335

336
#endif  // _BIT_ARRAY_DYNAMIC_EXTENT_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