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

PeterCDMcLean / BitLib / 15658406666

15 Jun 2025 02:12AM UTC coverage: 96.002% (+42.5%) from 53.519%
15658406666

Pull #17

github

web-flow
Merge 5e911f3b7 into 0f0b787a1
Pull Request #17: Truncation policy

122 of 148 new or added lines in 9 files covered. (82.43%)

4 existing lines in 3 files now uncovered.

1561 of 1626 relevant lines covered (96.0%)

20765048.89 hits per line

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

89.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_policy.hpp"
26
#include "bitlib/bit-containers/bit_span.hpp"
27
#include "bitlib/bit-iterator/bit.hpp"
28
#include "bitlib/bit_concepts.hpp"
29

30
namespace bit {
31
namespace detail {
32

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

61
 private:
62
  using word_type_ptr = word_type*;
63
  static const size_type FixedWords = sizeof(word_type_ptr) / sizeof(word_type);
64
  static const size_type FixedBits = FixedWords * bitsof<word_type>();
65

66
  const size_type m_size;
67

68
  struct Storage {
69
    union {
70
      word_type_ptr pointer;
71
      word_type fixed[FixedWords];
72
    };
73
    Allocator m_allocator;
74

75
    Storage(size_type words, const Allocator& allocator, detail::uninitialized_t) : m_allocator(allocator) {
74✔
76
      if (words > FixedWords) {
37✔
NEW
77
        new (&pointer) word_type_ptr(m_allocator.allocate(words));
×
78
      }
79
    }
37✔
80

81
    Storage(size_type words, const Allocator& allocator = Allocator()) : m_allocator(allocator) {
24✔
82
      if (words > FixedWords) {
12✔
83
        new (&pointer) word_type_ptr(m_allocator.allocate(words));
8✔
84
        for (size_type i = 0; i < words; ++i) {
67,701,776✔
85
          new (pointer + i) word_type();
67,701,772✔
86
        }
87
      } else {
88
        for (size_type i = 0; i < words; ++i) {
16✔
89
          new (&fixed[i]) word_type();
8✔
90
        }
91
      }
92
    }
12✔
93

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

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

137
  static constexpr size_type Words(size_type N) {
170✔
138
    return (N * bitsof<value_type>() + bitsof<word_type>() - 1) / bitsof<word_type>();
170✔
139
  };
140

141
 public:
142
  ~bit_array() {
55✔
143
    if (size() > FixedBits) {
55✔
144
      storage.m_allocator.deallocate(storage.pointer, Words(size()));
4✔
145
    } else {
146
      for (size_type i = 0; i < Words(size()); ++i) {
103✔
147
        storage.fixed[i].~word_type();
52✔
148
      }
149
    }
150
  }
55✔
151

152
  /*
153
  * Constructors, copies and moves...
154
  */
155
  bit_array() = delete;
156

157
  constexpr bit_array(const size_type size, const Allocator& allocator = Allocator())
12✔
158
      : m_size(size), storage(Words(size), allocator) {
12✔
159
  }
12✔
160

161
  template <std::integral U>
162
  constexpr bit_array(const size_type size, const U& integral, const Allocator& allocator = Allocator())
163
      : m_size(size), storage(Words(size), allocator, detail::uninitialized) {
164
    if (size() > bitsof<U>()) {
165
      Policy::truncation::template from_integral(*this, integral);
166
    } else {
167
      bit_pointer<U> integral_ptr = bit_pointer<U>(&integral);
168
      ::bit::copy(integral_ptr, integral_ptr + bitsof<U>(), begin());
169
    }
170
    if (size() < bitsof<U>()) {
171
      Policy::extension::template from_integral(*this, integral, detail::uninitialized);
172
    }
173
  }
174

175
  constexpr bit_array(const size_type size, const word_type val, const Allocator& allocator = Allocator())
176
      : m_size(size), storage(Words(size), val, allocator) {
177
  }
178

179
  constexpr bit_array(const size_type size, const value_type bit_val, const Allocator& allocator = Allocator())
22✔
180
    requires(!std::is_same<value_type, word_type>::value)
181
      : m_size(size), storage(Words(size), allocator, detail::uninitialized) {
22✔
182
    this->fill(bit_val);
22✔
183
  }
22✔
184

185
  constexpr bit_array(const bit_array<T, std::dynamic_extent, W, Policy>& other)
2✔
186
      : m_size(other.size()), storage(Words(size()), other.storage) {
6✔
187
  }
2✔
188

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

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

198
  constexpr bit_array(bit_array<T, std::dynamic_extent, W>&& other)
4✔
199
      : m_size(other.size()), storage(Words(size()), std::move(other.storage)) {
4✔
200
  }
4✔
201

202
  constexpr bit_array(bit_array<T, std::dynamic_extent, W>&& other, const Allocator& allocator)
203
      : m_size(other.size()), storage(Words(size()), std::move(other.storage), allocator) {
204
  }
205

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

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

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

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

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

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

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

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

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

291
  /*
292
   * Iterators
293
   */
294
  constexpr iterator begin() noexcept {
851✔
295
    if (size() > FixedBits) {
851✔
296
      return iterator(storage.pointer);
421✔
297
    } else {
298
      return iterator(storage.fixed);
430✔
299
    }
300
  }
301

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

310
  /*
311
   * Capacity
312
   */
313
  constexpr size_type size() const noexcept {
1,329✔
314
    return m_size;
1,329✔
315
  }
316

317
  /*
318
   * Operations
319
   */
320
  constexpr void swap(bit_array<T, std::dynamic_extent, W>& other) noexcept {
4✔
321
    assert(size() == other.size());
4✔
322
    if (size() > FixedBits) {
4✔
323
      std::swap(this->storage.pointer, other.storage.pointer);
×
324
    } else {
325
      for (size_type i = 0; i < Words(size()); ++i) {
8✔
326
        std::swap(this->storage.fixed[i], other.storage.fixed[i]);
4✔
327
      }
328
    }
329
  }
4✔
330
};
331

332
static_assert(bit_range<bit_array<>>, "bit_array<> does not satisfy bit_contiguous_range concept!");
333
static_assert(bit_sized_range<bit_array<>>, "bit_array<> does not satisfy bit_contiguous_sized_range concept!");
334
#ifdef CONTIGUOUS_RANGE
335
static_assert(bit_contiguous_range<bit_array<>>, "bit_array<> does not satisfy bit_contiguous_range concept!");
336
static_assert(bit_contiguous_sized_range<bit_array<>>, "bit_array<> does not satisfy bit_contiguous_sized_range concept!");
337
#endif
338

339
// ========================================================================== //
340
}  // namespace bit
341

342
#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

© 2026 Coveralls, Inc