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

PeterCDMcLean / BitLib / 15696998807

17 Jun 2025 02:58AM UTC coverage: 54.11% (+0.6%) from 53.519%
15696998807

push

github

web-flow
Truncation policy (#17)

* Add draft policies for integer conversion

* Add allocator to Policy. Use policy to construct from integral

* Add convenience conversion pathway for literal -> bit_value

* Add algorithm accumulate and utility to_string

* template keyword only necessary if actually passing template args

* Better UX for accumulate policy

* small tweaks to to_string

* Add static_assert error to bit_literal.

* Consolidate from_integral code

* Fix accumulate, get_word doesn't mask

10137 of 18710 branches covered (54.18%)

Branch coverage included in aggregate %.

212 of 251 new or added lines in 13 files covered. (84.46%)

214 existing lines in 11 files now uncovered.

6062 of 11227 relevant lines covered (53.99%)

7736453.1 hits per line

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

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

29
namespace bit {
30
namespace detail {
31

32
template <typename value_type, typename word_type>
33
struct bit_array_dextent_iterator_types {
34
  using iterator = typename std::conditional<std::is_same_v<value_type, bit_value>,
35
                                             bit_iterator<word_type*>,
36
                                             word_type*>::type;
37
  using const_iterator = typename std::conditional<std::is_same_v<value_type, bit_value>,
38
                                                   bit_iterator<const word_type*>,
39
                                                   const word_type*>::type;
40
};
41
}  // namespace detail
42
template <typename T, typename W, typename Policy>
43
class bit_array<T, std::dynamic_extent, W, Policy>
44
    : 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>> {
45
 public:
46
  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>>;
47
  using base::end;
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
  static const size_type FixedWords = sizeof(word_type_ptr) / sizeof(word_type);
63
  static const size_type FixedBits = FixedWords * bitsof<word_type>();
64

65
  const size_type m_size;
66

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

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

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

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

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

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

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

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

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

160
  template <std::integral U>
161
  constexpr bit_array(const size_type size, const U& integral, const Allocator& allocator = Allocator())
162
      : m_size(size), storage(Words(size), allocator, detail::uninitialized) {
163
    this->from_integral(integral);
164
  }
165

166
  constexpr bit_array(const size_type size, const word_type val, const Allocator& allocator = Allocator())
167
      : m_size(size), storage(Words(size), val, allocator) {
168
  }
169

170
  constexpr bit_array(const size_type size, const value_type bit_val, const Allocator& allocator = Allocator())
22✔
171
    requires(!std::is_same<value_type, word_type>::value)
172
      : m_size(size), storage(Words(size), allocator, detail::uninitialized) {
44✔
173
    this->fill(bit_val);
44✔
174
  }
44✔
175

176
  constexpr bit_array(const bit_array<T, std::dynamic_extent, W, Policy>& other)
2✔
177
      : m_size(other.size()), storage(Words(size()), other.storage) {
8✔
178
  }
4✔
179

180
  constexpr bit_array(const bit_array<T, std::dynamic_extent, W, Policy>& other, const Allocator& allocator)
181
      : m_size(other.size()), storage(Words(size()), other.storage, allocator) {
182
  }
183

184
  constexpr bit_array(const bit_sized_range auto& other, const Allocator& allocator = Allocator())
185
      : bit_array(other.size(), allocator, detail::uninitialized) {
186
    ::bit::copy(other.begin(), other.end(), this->begin());
187
  }
188

189
  constexpr bit_array(bit_array<T, std::dynamic_extent, W>&& other)
4✔
190
      : m_size(other.size()), storage(Words(size()), std::move(other.storage)) {
8✔
191
  }
8✔
192

193
  constexpr bit_array(bit_array<T, std::dynamic_extent, W>&& other, const Allocator& allocator)
194
      : m_size(other.size()), storage(Words(size()), std::move(other.storage), allocator) {
195
  }
196

197
  constexpr bit_array(const std::initializer_list<value_type> init, const Allocator& allocator = Allocator())
12✔
198
    requires(!std::is_same_v<value_type, word_type>)
199
      : m_size(init.size()), storage(Words(size()), allocator, detail::uninitialized) {
24✔
200
    std::copy(init.begin(), init.end(), this->begin());
24✔
201
  }
24✔
202

203
#if 0
204
  No known conversion from bool to bit_value
205
  bit_value has explicit constructor from bool to bit_value so this doesnt work
206
  constexpr bit_array<std::dynamic_extent,W>::bit_array(const std::initializer_list<bool> init)
207
      : storage(std::make_unique<word_type[]>(Words(init.size()))),
208
        m_size(init.size()) {
209
    std::copy(init.begin(), init.end(), this->begin());
210
  }
211
#endif
212

213
  template <typename U>
214
  constexpr bit_array(const std::initializer_list<U> init, const Allocator& allocator = Allocator())
1✔
215
      : m_size(bitsof<U>() * init.size()), storage(Words(size()), allocator, detail::uninitialized) {
2✔
216
    std::copy(init.begin(), init.end(), data());
2✔
217
  }
2✔
218

219
  constexpr bit_array(const std::string_view s, const Allocator& allocator = Allocator())
2✔
220
    requires(std::is_same_v<value_type, bit_value>)
221
      : m_size(std::count(s.begin(), s.end(), '0') + std::count(s.begin(), s.end(), '1')), storage(Words(size()), allocator, detail::uninitialized) {
4✔
222
    size_type i = 0;
4✔
223
    for (char c : s) {
32✔
224
      if (c == '0') {
30✔
225
        begin()[i++] = bit0;
14✔
226
      } else if (c == '1') {
16!
227
        begin()[i++] = bit1;
16✔
228
      }
8✔
229
    }
15✔
230
  }
4✔
231

232
  /*
233
   * Assignment
234
   */
235
  constexpr bit_array<T, std::dynamic_extent, W>& operator=(const bit_array<T, std::dynamic_extent, W>& other) {
6✔
236
    if (nullptr == data() || size() != other.size()) {
6!
237
      throw std::invalid_argument("Cannot reassign bit_array<std::dynamic_extent,V,W> size");
4✔
238
    }
2✔
239
    if (this == &other) [[unlikely]] {
2!
240
      return *this;
×
UNCOV
241
    }
242
    std::copy(other.begin(), other.end(), this->begin());
2✔
243
    return *this;
2✔
244
  }
1✔
245

246
  constexpr bit_array<T, std::dynamic_extent, W>& operator=(const bit_sized_range auto& other) {
4✔
247
    if (other.size() != this->size()) [[unlikely]] {
4✔
248
      throw std::invalid_argument("other bit_range contains an invalid number of bits for bit_array.");
2✔
249
    }
1✔
250
    ::bit::copy(other.begin(), other.end(), this->begin());
2✔
251
    return *this;
3✔
252
  };
2✔
253

254
  constexpr bit_array<T, std::dynamic_extent, W>& operator=(bit_array<T, std::dynamic_extent, W>&& other) {
8✔
255
    if (nullptr == data() || size() != other.size()) {
8!
256
      throw std::invalid_argument("Cannot reassign bit_array<std::dynamic_extent,V,W> size");
2✔
257
    }
1✔
258
    bit_array<T, std::dynamic_extent, W> temp(std::move(other));
6✔
259
    swap(temp);
6✔
260
    return *this;
9✔
261
  }
7✔
262

263
  /*
264
   * Element Access
265
   */
266
  constexpr word_type* data() noexcept {
36✔
267
    if (size() > FixedBits) {
36!
NEW
268
      return storage.pointer;
×
269
    } else {
18✔
270
      return storage.fixed;
36✔
271
    }
18✔
272
  }
18✔
273

274
  constexpr const word_type* data() const noexcept {
275
    if (size() > FixedBits) {
276
      return storage.pointer;
277
    } else {
278
      return storage.fixed;
279
    }
280
  }
281

282
  /*
283
   * Iterators
284
   */
285
  constexpr iterator begin() noexcept {
1,702✔
286
    if (size() > FixedBits) {
1,702!
287
      return iterator(storage.pointer);
842✔
288
    } else {
430✔
289
      return iterator(storage.fixed);
860✔
290
    }
430✔
291
  }
851✔
292

293
  constexpr const_iterator begin() const noexcept {
44✔
294
    if (size() > FixedBits) {
44!
NEW
295
      return const_iterator(storage.pointer);
×
296
    } else {
22✔
297
      return const_iterator(storage.fixed);
44✔
298
    }
22✔
299
  }
22✔
300

301
  /*
302
   * Capacity
303
   */
304
  constexpr size_type size() const noexcept {
2,658✔
305
    return m_size;
2,658✔
306
  }
1,329✔
307

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

323
static_assert(bit_range<bit_array<>>, "bit_array<> does not satisfy bit_contiguous_range concept!");
324
static_assert(bit_sized_range<bit_array<>>, "bit_array<> does not satisfy bit_contiguous_sized_range concept!");
325
#ifdef CONTIGUOUS_RANGE
326
static_assert(bit_contiguous_range<bit_array<>>, "bit_array<> does not satisfy bit_contiguous_range concept!");
327
static_assert(bit_contiguous_sized_range<bit_array<>>, "bit_array<> does not satisfy bit_contiguous_sized_range concept!");
328
#endif
329

330
// ========================================================================== //
331
}  // namespace bit
332

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