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

PeterCDMcLean / BitLib / 14919535413

09 May 2025 01:36AM UTC coverage: 96.956% (-0.08%) from 97.036%
14919535413

Pull #8

github

web-flow
Merge 708ead0cd into a837637fd
Pull Request #8: Common bit array base

36 of 38 new or added lines in 2 files covered. (94.74%)

4 existing lines in 3 files now uncovered.

1274 of 1314 relevant lines covered (96.96%)

16656585.79 hits per line

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

96.81
/include/bitlib/bit-containers/bit_array_dynamic_extent.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_DYNAMIC_EXTENT_HPP_INCLUDED
10
#define _BIT_ARRAY_DYNAMIC_EXTENT_HPP_INCLUDED
11

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

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

28
namespace bit {
29
namespace detail {
30
template <typename value_type, typename word_type>
31
using bit_array_it = typename std::conditional<std::is_same_v<value_type, bit_value>,
32
                                               bit_iterator<word_type*>,
33
                                               word_type*>::type;
34
template <typename value_type, typename word_type>
35
using bit_array_cit = typename std::conditional<std::is_same_v<value_type, bit_value>,
36
                                                bit_iterator<const word_type*>,
37
                                                const word_type*>::type;
38
}  // namespace detail
39
template <typename T, std::align_val_t V, typename W>
40
class bit_array<T, std::dynamic_extent, V, W>
41
    : public bit_array_base<bit_array<T, std::dynamic_extent, V, W>, T, W, detail::bit_array_it<T, W>, detail::bit_array_cit<T, W>> {
42
 public:
43
  using typename bit_array_base<bit_array<T, std::dynamic_extent, V, W>, T, W, detail::bit_array_it<T, W>, detail::bit_array_cit<T, W>>::word_type;
44
  using typename bit_array_base<bit_array<T, std::dynamic_extent, V, W>, T, W, detail::bit_array_it<T, W>, detail::bit_array_cit<T, W>>::value_type;
45
  using typename bit_array_base<bit_array<T, std::dynamic_extent, V, W>, T, W, detail::bit_array_it<T, W>, detail::bit_array_cit<T, W>>::size_type;
46
  using typename bit_array_base<bit_array<T, std::dynamic_extent, V, W>, T, W, detail::bit_array_it<T, W>, detail::bit_array_cit<T, W>>::difference_type;
47
  using typename bit_array_base<bit_array<T, std::dynamic_extent, V, W>, T, W, detail::bit_array_it<T, W>, detail::bit_array_cit<T, W>>::reference;
48
  using typename bit_array_base<bit_array<T, std::dynamic_extent, V, W>, T, W, detail::bit_array_it<T, W>, detail::bit_array_cit<T, W>>::const_reference;
49
  using typename bit_array_base<bit_array<T, std::dynamic_extent, V, W>, T, W, detail::bit_array_it<T, W>, detail::bit_array_cit<T, W>>::pointer;
50
  using typename bit_array_base<bit_array<T, std::dynamic_extent, V, W>, T, W, detail::bit_array_it<T, W>, detail::bit_array_cit<T, W>>::const_pointer;
51
  using typename bit_array_base<bit_array<T, std::dynamic_extent, V, W>, T, W, detail::bit_array_it<T, W>, detail::bit_array_cit<T, W>>::iterator;
52
  using typename bit_array_base<bit_array<T, std::dynamic_extent, V, W>, T, W, detail::bit_array_it<T, W>, detail::bit_array_cit<T, W>>::const_iterator;
53

54
 private:
55
  struct deleter {
56
    size_type words;
57
    void operator()(word_type* const p) const {
61✔
58
      for (size_type i = 0; i < words; ++i) {
541,614,319✔
59
        (p + i)->~word_type();
541,614,258✔
60
      }
61
      ::operator delete(p, V);
61✔
62
    }
61✔
63
  };
64

65
  const size_type m_size;
66
  const std::unique_ptr<word_type[], deleter> storage;
67
  static constexpr size_type Words(size_type N) {
541,614,444✔
68
    return (N * bitsof<value_type>() + bitsof<word_type>() - 1) / bitsof<word_type>();
541,614,444✔
69
  };
70
  static constexpr size_t AlignedBytes(size_t N) {
61✔
71
    return (Words(N) * sizeof(word_type) + static_cast<size_t>(V) - 1) & ~(static_cast<size_t>(V) - 1);
61✔
72
  };
73

74
 public:
75
  /*
76
  * Constructors, copies and moves...
77
  */
78
  bit_array() = delete;
79
  constexpr bit_array(const size_type size);
80
  template <std::integral U>
81
  constexpr bit_array(const size_type size, const U& integral);
82
  constexpr bit_array(const size_type size, const value_type bit_val);
83
  constexpr bit_array(const bit_array<T, std::dynamic_extent, V, W>& other);
84
  constexpr bit_array(const bit_array<T, std::dynamic_extent, V, W>&& other);
85
  constexpr bit_array(const std::initializer_list<value_type> init)
86
    requires(!std::is_same_v<value_type, word_type>);
87
#if 0
88
  constexpr bit_array(const std::initializer_list<bool> init);
89
#endif
90
  constexpr bit_array(const std::initializer_list<word_type> init);
91
  constexpr bit_array(const std::string_view s)
92
    requires(std::is_same_v<value_type, bit_value>);
93

94
  ~bit_array() = default;
122✔
95
  /*
96
     * Assignment
97
     */
98
  constexpr bit_array<T, std::dynamic_extent, V, W>& operator=(const bit_array<T, std::dynamic_extent, V, W>& other);
99
  constexpr bit_array<T, std::dynamic_extent, V, W>& operator=(bit_array<T, std::dynamic_extent, V, W>&& other);
100

101
  // Comparison from base class
102

103
  /*
104
     * Element Access
105
     */
106
  constexpr word_type* data() noexcept;
107
  constexpr const word_type* data() const noexcept;
108

109
  /*
110
     * Iterators
111
     */
112
  constexpr iterator begin() noexcept;
113
  constexpr iterator end() noexcept;
114
  constexpr const_iterator begin() const noexcept;
115
  constexpr const_iterator end() const noexcept;
116
  constexpr const_iterator cbegin() const noexcept;
117
  constexpr const_iterator cend() const noexcept;
118

119
  /*
120
     * Capacity
121
     */
122
  constexpr size_type size() const noexcept;
123

124
  /*
125
    * Slice
126
  */
127
  // Slice operators are provided by the base class
128

129
  /*
130
     * Operations
131
     */
132
  // Common operations
133
  // Fill is provided by the base class
134
  constexpr void swap(bit_array<T, std::dynamic_extent, V, W>& other) noexcept;
135
  template <std::integral U>
136
  explicit constexpr operator U() const noexcept;
137

138
  // String representation
139
  // debug_string is provided by the base class
140
};
141

142
static_assert(bit_range<bit_array<>>, "bit_array<> does not satisfy bit_contiguous_range concept!");
143
static_assert(bit_sized_range<bit_array<>>, "bit_array<> does not satisfy bit_contiguous_sized_range concept!");
144
#ifdef CONTIGUOUS_RANGE
145
static_assert(bit_contiguous_range<bit_array<>>, "bit_array<> does not satisfy bit_contiguous_range concept!");
146
static_assert(bit_contiguous_sized_range<bit_array<>>, "bit_array<> does not satisfy bit_contiguous_sized_range concept!");
147
#endif
148

149
/* Can't imagine any use for a default constructor
150
template <typename T, std::align_val_t V, typename W>
151
constexpr bit_array<T, std::dynamic_extent, V, W>::bit_array() noexcept
152
    : m_size(0), storage(std::unique_ptr<word_type[], decltype(&std::free)>(nullptr, &std::free)) {
153
}
154
*/
155

156
template <typename T, std::align_val_t V, typename W>
157
template <std::integral U>
158
constexpr bit_array<T, std::dynamic_extent, V, W>::bit_array(const size_type size, const U& integral)
159
    : m_size(size),
160
      storage(static_cast<word_type*>(::operator new(AlignedBytes(m_size), V)), deleter{Words(m_size)}) {
161
  assert (bitsof<U>() <= size);
162
  for (size_type i = 0; i < Words(m_size); ++i) {
163
    new (storage.get() + i) word_type();
164
  }
165
  std::memcpy(storage.get(), &integral, sizeof(integral));
166
  bool sign_extend = false;
167
  if constexpr (std::is_signed_v<U>) {
168
    sign_extend = (integral & (1 << (bitsof<U>()-1))) ? true : false;
169
  }
170
  if (sign_extend) {
171
    for (auto it = begin()+bitsof<U>(); it != end(); ++it) {
172
      *it = bit1;
173
    }
174
  } else {
175
    for (auto it = begin()+bitsof<U>(); it != end(); ++it) {
176
      *it = bit0;
177
    }
178
  }
179
}
180

181
template <typename T, std::align_val_t V, typename W>
182
constexpr bit_array<T, std::dynamic_extent, V, W>::bit_array(const size_type size)
8✔
183
    : m_size(size),
8✔
184
      storage(static_cast<word_type*>(::operator new(AlignedBytes(m_size), V)), deleter{Words(m_size)}) {
8✔
185
  //std::uninitialized_fill_n(this->begin(), Words(m_size), word_type());
186
  for (size_type i = 0; i < Words(m_size); ++i) {
541,614,174✔
187
    new (storage.get() + i) word_type();
541,614,166✔
188
  }
189
}
8✔
190

191
template <typename T, std::align_val_t V, typename W>
192
constexpr bit_array<T, std::dynamic_extent, V, W>::bit_array(const size_type size, const value_type bit_val)
14✔
193
    : m_size(size),
14✔
194
      storage(static_cast<word_type*>(::operator new(AlignedBytes(m_size), V)), deleter{Words(m_size)}) {
14✔
195
  if constexpr (std::is_same<value_type, word_type>::value) {
196
    for (size_type i = 0; i < Words(m_size); ++i) {
34✔
197
      new (storage.get() + i) word_type(bit_val);
32✔
198
    }
199
  } else {
200
    for (size_type i = 0; i < Words(m_size); ++i) {
32✔
201
      new (storage.get() + i) word_type();
20✔
202
    }
203
    this->fill(bit_val);
12✔
204
  }
205
}
14✔
206

207
template <typename T, std::align_val_t V, typename W>
208
constexpr bit_array<T, std::dynamic_extent, V, W>::bit_array(const bit_array<T, std::dynamic_extent, V, W>& other)
33✔
209
    : m_size(other.size()),
33✔
210
      storage(static_cast<word_type*>(::operator new(AlignedBytes(m_size), V)), deleter{Words(m_size)}) {
33✔
211
  for (size_type i = 0; i < Words(m_size); ++i) {
66✔
212
    new (storage.get() + i) word_type(*(other.storage.get() + i));
33✔
213
  }
214
}
33✔
215

216
template <typename T, std::align_val_t V, typename W>
217
constexpr bit_array<T, std::dynamic_extent, V, W>::bit_array(const bit_array<T, std::dynamic_extent, V, W>&& other)
1✔
218
    : m_size(other.size()),
1✔
219
      storage(static_cast<word_type*>(::operator new(AlignedBytes(m_size), V)), deleter{Words(m_size)}) {
1✔
220
  for (size_type i = 0; i < Words(m_size); ++i) {
2✔
221
    new (storage.get() + i) word_type(*(other.storage.get() + i));
1✔
222
  }
223
}
1✔
224

225
template <typename T, std::align_val_t V, typename W>
226
constexpr bit_array<T, std::dynamic_extent, V, W>::bit_array(const std::initializer_list<value_type> init)
2✔
227
  requires(!std::is_same_v<value_type, word_type>)
228
    : m_size(init.size()),
2✔
229
      storage(static_cast<word_type*>(::operator new(AlignedBytes(m_size), V)), deleter{Words(m_size)}) {
2✔
230
  for (size_type i = 0; i < Words(m_size); ++i) {
4✔
231
    new (storage.get() + i) word_type();
2✔
232
  }
233
  std::copy(init.begin(), init.end(), this->begin());
2✔
234
}
2✔
235

236
#if 0
237
No known conversion from bool to bit_value
238
bit_value has explicit constructor from bool to bit_value so this doesnt work
239
constexpr bit_array<std::dynamic_extent,W>::bit_array(const std::initializer_list<bool> init)
240
    : storage(std::make_unique<word_type[]>(Words(init.size()))),
241
      m_size(init.size()) {
242
  std::copy(init.begin(), init.end(), this->begin());
243
}
244
#endif
245

246
template <typename T, std::align_val_t V, typename W>
247
constexpr bit_array<T, std::dynamic_extent, V, W>::bit_array(const std::initializer_list<word_type> init)
1✔
248
    : m_size(bitsof<word_type>() * init.size()),
1✔
249
      storage(static_cast<word_type*>(::operator new(AlignedBytes(m_size), V)), deleter{Words(m_size)}) {
1✔
250
  size_type i = 0;
1✔
251
  auto it = init.begin();
1✔
252
  for (; i < Words(m_size) && it != init.end(); ++i, ++it) {
3✔
253
    new (storage.get() + i) word_type(*it);
2✔
254
  }
255
  // Initialize remaining words if any
256
  for (; i < Words(m_size); ++i) {
1✔
NEW
257
    new (storage.get() + i) word_type();
×
258
  }
259
}
1✔
260

261
template <typename T, std::align_val_t V, typename W>
262
constexpr bit_array<T, std::dynamic_extent, V, W>::bit_array(const std::string_view s)
2✔
263
  requires(std::is_same_v<value_type, bit_value>)
264
    : m_size((std::count(s.begin(), s.end(), '0') + std::count(s.begin(), s.end(), '1'))),
2✔
265
      storage(static_cast<word_type*>(::operator new(AlignedBytes(m_size), V)), deleter{Words(m_size)}) {
2✔
266
  for (size_type i = 0; i < Words(m_size); ++i) {
4✔
267
    new (storage.get() + i) word_type();
2✔
268
  }
269
  size_type i = 0;
2✔
270
  for (char c : s) {
17✔
271
    if (c == '0') {
15✔
272
      begin()[i++] = bit0;
7✔
273
    } else if (c == '1') {
8✔
274
      begin()[i++] = bit1;
8✔
275
    }
276
  }
277
}
2✔
278

279
template <typename T, std::align_val_t V, typename W>
280
constexpr bit_array<T, std::dynamic_extent, V, W>& bit_array<T, std::dynamic_extent, V, W>::operator=(const bit_array<T, std::dynamic_extent, V, W>& other) {
1✔
281
  if (nullptr == storage.get() || m_size != other.m_size) {
1✔
UNCOV
282
    throw std::invalid_argument("Cannot reassign bit_array<std::dynamic_extent,V,W> size");
×
283
  }
284
  std::copy(other.begin(), other.end(), this->begin());
1✔
285
  return *this;
2✔
286
}
287

288
template <typename T, std::align_val_t V, typename W>
289
constexpr bit_array<T, std::dynamic_extent, V, W>& bit_array<T, std::dynamic_extent, V, W>::operator=(bit_array<T, std::dynamic_extent, V, W>&& other) {
1✔
290
  if (nullptr == storage.get() || m_size != other.m_size) {
1✔
UNCOV
291
    throw std::invalid_argument("Cannot reassign bit_array<std::dynamic_extent,V,W> size");
×
292
  }
293
  std::copy(other.begin(), other.end(), this->begin());
1✔
294
  return *this;
2✔
295
}
296

297
template <typename T, std::align_val_t V, typename W>
298
constexpr void bit_array<T, std::dynamic_extent, V, W>::swap(bit_array<T, std::dynamic_extent, V, W>& other) noexcept {
1✔
299
  assert(this->m_size == other.m_size);
1✔
300
  W* it1 = this->storage.get();
1✔
301
  W* it2 = other.storage.get();
1✔
302
  for (size_type i = 0; i < Words(this->m_size); i++, it1++, it2++) {
2✔
303
    std::swap(*it1, *it2);
1✔
304
  }
305
}
1✔
306

307
// fill method is now provided by the base class
308

309
// -------------------------------------------------------------------------- //
310
/*
311
    * Element Access
312
    */
313
template <typename T, std::align_val_t V, typename W>
314
constexpr typename bit_array<T, std::dynamic_extent, V, W>::word_type* bit_array<T, std::dynamic_extent, V, W>::data() noexcept {
1✔
315
  return size() ? storage.get() : nullptr;
1✔
316
}
317

318
template <typename T, std::align_val_t V, typename W>
319
constexpr const typename bit_array<T, std::dynamic_extent, V, W>::word_type* bit_array<T, std::dynamic_extent, V, W>::data() const noexcept {
320
  return size() ? storage.get() : nullptr;
321
}
322

323
// -------------------------------------------------------------------------- //
324

325
template <typename T, std::align_val_t V, typename W>
326
constexpr typename bit_array<T, std::dynamic_extent, V, W>::size_type bit_array<T, std::dynamic_extent, V, W>::size() const noexcept { return m_size; }
218✔
327

328
// Iterators
329
// -------------------------------------------------------------------------- //
330

331
template <typename T, std::align_val_t V, typename W>
332
constexpr typename bit_array<T, std::dynamic_extent, V, W>::iterator bit_array<T, std::dynamic_extent, V, W>::begin() noexcept {
585✔
333
  return iterator(storage.get());
585✔
334
}
335

336
template <typename T, std::align_val_t V, typename W>
337
constexpr typename bit_array<T, std::dynamic_extent, V, W>::iterator bit_array<T, std::dynamic_extent, V, W>::end() noexcept {
25✔
338
  return begin() + size();
25✔
339
}
340

341
template <typename T, std::align_val_t V, typename W>
342
constexpr typename bit_array<T, std::dynamic_extent, V, W>::const_iterator bit_array<T, std::dynamic_extent, V, W>::begin() const noexcept {
5✔
343
  return const_iterator(storage.get());
5✔
344
}
345

346
template <typename T, std::align_val_t V, typename W>
347
constexpr typename bit_array<T, std::dynamic_extent, V, W>::const_iterator bit_array<T, std::dynamic_extent, V, W>::end() const noexcept {
3✔
348
  return const_iterator(storage.get()) + size();
3✔
349
}
350

351
template <typename T, std::align_val_t V, typename W>
352
constexpr typename bit_array<T, std::dynamic_extent, V, W>::const_iterator bit_array<T, std::dynamic_extent, V, W>::cbegin() const noexcept {
353
  return const_iterator(storage.get());
354
}
355

356
template <typename T, std::align_val_t V, typename W>
357
constexpr typename bit_array<T, std::dynamic_extent, V, W>::const_iterator bit_array<T, std::dynamic_extent, V, W>::cend() const noexcept {
358
  return const_iterator(storage.get()) + size();
359
}
360

361
// -------------------------------------------------------------------------- //
362

363
// Slice operators are now provided by the base class
364

365
template <typename T, std::align_val_t V, typename W>
366
template <std::integral U>
367
constexpr bit_array<T, std::dynamic_extent, V, W>::operator U() const noexcept {
368
  assert(size() <= bitsof<U>());
369
  U result{};
370
  std::memcpy(&result, storage.get(), std::min(sizeof(U), Words(m_size) * sizeof(word_type)));
371

372
  if constexpr (std::is_signed_v<U>) {
373
    if (size() > 0 && begin()[size() - 1]) {
374
      for (size_type i = size(); i < bitsof<U>(); ++i) {
375
        result |= (static_cast<U>(1) << i);
376
      }
377
    } else {
378
      for (size_type i = size(); i < bitsof<U>(); ++i) {
379
        result &= ~(static_cast<U>(1) << i);
380
      }
381
    }
382
  }
383
  return result;
384
}
385

386
// ========================================================================== //
387
}  // namespace bit
388

389
#endif  // _BIT_ARRAY_DYNAMIC_EXTENT_HPP_INCLUDED
390
        // ========================================================================== //
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