spot 2.16
Loading...
Searching...
No Matches
bitvect.hh
1// -*- coding: utf-8 -*-
2// Copyright (C) by the Spot authors, see the AUTHORS file for details.
3//
4// This file is part of Spot, a model checking library.
5//
6// Spot is free software; you can redistribute it and/or modify it
7// under the terms of the GNU General Public License as published by
8// the Free Software Foundation; either version 3 of the License, or
9// (at your option) any later version.
10//
11// Spot is distributed in the hope that it will be useful, but WITHOUT
12// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14// License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19#pragma once
20
21#include <spot/misc/common.hh>
22#include <cstddef>
23#include <cstdlib>
24#include <cassert>
25#include <iosfwd>
26#include <iostream>
27#include <algorithm>
28#include <new>
29
30namespace spot
31{
34
35 class bitvect;
36 class bitvect_array;
37
41 SPOT_API bitvect* make_bitvect(size_t bitcount);
42
46 SPOT_API bitvect_array* make_bitvect_array(size_t bitcount,
47 size_t vectcount);
48
50 class SPOT_API bitvect
51 {
52 private:
53 // Used by make_bitvect to construct a large bitvect in place.
54 bitvect(size_t size, size_t block_count);
55 bitvect(size_t size, size_t block_count, bool);
56
57 public:
58 typedef unsigned long block_t;
59
60 bitvect():
61 size_(0),
62 block_count_(1),
63 storage_(&local_storage_),
64 local_storage_(0)
65 {
66 }
67
69 bitvect(const bitvect& other):
70 size_(other.size_),
71 block_count_(1),
72 storage_(&local_storage_)
73 {
74 *this = other;
75 }
76
77 bitvect* clone() const;
78
80 void operator delete(void *ptr)
81 {
82 // This object was allocated using a placement new.
83 ::operator delete(ptr);
84 }
85
88 {
89 size_ = 0;
90 }
91
93 bitvect& operator=(const bitvect& other)
94 {
95 reserve_blocks(other.block_count_);
96 size_ = other.size();
97 for (size_t i = 0; i < block_count_; ++i)
98 storage_[i] = other.storage_[i];
99 return *this;
100 }
101
102 ~bitvect()
103 {
104 if (storage_ != &local_storage_)
105 free(storage_);
106 }
107
111 void reserve_blocks(size_t new_block_count)
112 {
113 if (new_block_count < block_count_)
114 return;
115 if (storage_ == &local_storage_)
116 {
117 block_t* new_storage = static_cast<block_t*>
118 (malloc(new_block_count * sizeof(block_t)));
119 if (SPOT_UNLIKELY(!new_storage))
120 throw std::bad_alloc();
121 for (size_t i = 0; i < block_count_; ++i)
122 new_storage[i] = storage_[i];
123 storage_ = new_storage;
124 }
125 else
126 {
127 block_t* new_storage = static_cast<block_t*>
128 (realloc(storage_, new_block_count * sizeof(block_t)));
129 if (SPOT_UNLIKELY(!new_storage))
130 // storage_, untouched, will be freed by the destructor.
131 throw std::bad_alloc();
132 storage_ = new_storage;
133 }
134 block_count_ = new_block_count;
135 }
136
137 private:
138 void grow()
139 {
140 size_t new_block_count = (block_count_ + 1) * 7 / 5;
141 reserve_blocks(new_block_count);
142 }
143
144 public:
145
147 size_t used_blocks() const
148 {
149 const size_t bpb = 8 * sizeof(block_t);
150 return (size_ + bpb - 1) / bpb;
151 }
152
154 size_t size() const
155 {
156 return size_;
157 }
158
160 size_t capacity() const
161 {
162 return 8 * block_count_ * sizeof(block_t);
163 }
164
166 size_t hash() const noexcept;
167
169 bool get(size_t pos) const
170 {
171 SPOT_ASSERT(pos < size_);
172 const size_t bpb = 8 * sizeof(block_t);
173 return storage_[pos / bpb] & (1UL << (pos % bpb));
174 }
175
178 {
179 for (size_t i = 0; i < block_count_; ++i)
180 storage_[i] = 0;
181 }
182
184 bool is_fully_clear() const
185 {
186 size_t i;
187 const size_t bpb = 8 * sizeof(bitvect::block_t);
188 size_t rest = size() % bpb;
189 for (i = 0; i < block_count_ - !!rest; ++i)
190 if (storage_[i] != 0)
191 return false;
192 // The last block might not be fully used, compare only the
193 // relevant portion.
194 if (!rest)
195 return true;
196 block_t mask = (1UL << rest) - 1;
197 return (storage_[i] & mask) == 0;
198 }
199
201 bool is_fully_set() const
202 {
203 size_t i;
204 const size_t bpb = 8 * sizeof(bitvect::block_t);
205 size_t rest = size() % bpb;
206 for (i = 0; i < block_count_ - !!rest; ++i)
207 if (storage_[i] != -1UL)
208 return false;
209 if (!rest)
210 return true;
211 // The last block might not be fully used, compare only the
212 // relevant portion.
213 block_t mask = (1UL << rest) - 1;
214 return ((~storage_[i]) & mask) == 0;
215 }
216
218 void set_all()
219 {
220 for (size_t i = 0; i < block_count_; ++i)
221 storage_[i] = -1UL;
222 }
223
225 void flip_all()
226 {
227 for (size_t i = 0; i < block_count_; ++i)
228 storage_[i] = ~storage_[i];
229 }
230
232 void set(size_t pos)
233 {
234 SPOT_ASSERT(pos < size_);
235 const size_t bpb = 8 * sizeof(block_t);
236 storage_[pos / bpb] |= 1UL << (pos % bpb);
237 }
238
240 void clear(size_t pos)
241 {
242 SPOT_ASSERT(pos < size_);
243 const size_t bpb = 8 * sizeof(block_t);
244 storage_[pos / bpb] &= ~(1UL << (pos % bpb));
245 }
246
248 void flip(size_t pos)
249 {
250 SPOT_ASSERT(pos < size_);
251 const size_t bpb = 8 * sizeof(block_t);
252 storage_[pos / bpb] ^= (1UL << (pos % bpb));
253 }
254
255
258 {
259 SPOT_ASSERT(other.size_ <= size_);
260 unsigned m = std::min(other.block_count_, block_count_);
261 for (size_t i = 0; i < m; ++i)
262 storage_[i] |= other.storage_[i];
263 return *this;
264 }
265
268 {
269 SPOT_ASSERT(other.size_ <= size_);
270 unsigned m = std::min(other.block_count_, block_count_);
271 for (size_t i = 0; i < m; ++i)
272 storage_[i] &= other.storage_[i];
273 return *this;
274 }
275
277 bitvect& add_common(const bitvect& other1, const bitvect& other2)
278 {
279 SPOT_ASSERT(other1.size_ <= size_ && other2.size_ <= size_);
280 unsigned m = std::min(other2.block_count_,
281 std::min(other1.block_count_, block_count_));
282 for (size_t i = 0; i < m; ++i)
283 storage_[i] |= other1.storage_[i] & other2.storage_[i];
284 return *this;
285 }
286
288 bool intersects(const bitvect& other)
289 {
290 SPOT_ASSERT(other.size_ <= size_);
291 unsigned m = std::min(other.block_count_, block_count_);
292 for (size_t i = 0; i < m; ++i)
293 if (storage_[i] & other.storage_[i])
294 return true;
295 return false;
296 }
297
300 {
301 SPOT_ASSERT(other.size_ <= size_);
302 unsigned m = std::min(other.block_count_, block_count_);
303 for (size_t i = 0; i < m; ++i)
304 storage_[i] ^= other.storage_[i];
305 return *this;
306 }
307
310 {
311 SPOT_ASSERT(other.block_count_ <= block_count_);
312 for (size_t i = 0; i < other.block_count_; ++i)
313 storage_[i] &= ~other.storage_[i];
314 return *this;
315 }
316
318 bool is_subset_of(const bitvect& other) const
319 {
320 SPOT_ASSERT(other.block_count_ >= block_count_);
321
322 size_t i;
323 const size_t bpb = 8 * sizeof(bitvect::block_t);
324 size_t rest = size() % bpb;
325 for (i = 0; i < block_count_ - !!rest; ++i)
326 if ((storage_[i] & other.storage_[i]) != storage_[i])
327 return false;
328 if (!rest)
329 return true;
330
331 // The last block might not be fully used, compare only the
332 // relevant portion.
333 block_t mask = (1UL << rest) - 1;
334 return ((storage_[i] & mask & other.storage_[i])
335 == (storage_[i] & mask));
336 }
337
339 unsigned count() const
340 {
341 size_t i;
342 const size_t bpb = 8 * sizeof(bitvect::block_t);
343 size_t rest = size() % bpb;
344 size_t c = 0;
345 for (i = 0; i < block_count_; ++i)
346 {
347 block_t v = storage_[i];
348 if ((i == block_count_ - 1) && rest)
349 // The last block might not be fully used, scan only the
350 // relevant portion.
351 v &= (1UL << rest) - 1;
352#ifdef __GNUC__
353 c += __builtin_popcountl(v);
354#else
355 while (v)
356 {
357 ++c;
358 v &= v - 1;
359 }
360#endif
361 }
362 return c;
363 }
364
366 bool operator==(const bitvect& other) const
367 {
368 if (other.size_ != size_)
369 return false;
370 if (size_ == 0)
371 return true;
372 size_t i;
373 size_t m = other.used_blocks();
374 const size_t bpb = 8 * sizeof(bitvect::block_t);
375 size_t rest = size() % bpb;
376 for (i = 0; i < m - !!rest; ++i)
377 if (storage_[i] != other.storage_[i])
378 return false;
379 if (!rest)
380 return true;
381 // The last block might not be fully used, compare only the
382 // relevant portion.
383 block_t mask = (1UL << rest) - 1;
384 return (storage_[i] & mask) == (other.storage_[i] & mask);
385 }
386
388 bool operator!=(const bitvect& other) const
389 {
390 return !(*this == other);
391 }
392
394 bool operator<(const bitvect& other) const
395 {
396 if (size_ != other.size_)
397 return size_ < other.size_;
398 if (size_ == 0)
399 return false;
400 size_t i;
401 size_t m = other.used_blocks();
402 const size_t bpb = 8 * sizeof(bitvect::block_t);
403 size_t rest = size() % bpb;
404 for (i = 0; i < m - !!rest; ++i)
405 if (storage_[i] > other.storage_[i])
406 return false;
407 if (!rest)
408 return true;
409 // The last block might not be fully used, compare only the
410 // relevant portion.
411 block_t mask = (1UL << rest) - 1;
412 return (storage_[i] & mask) < (other.storage_[i] & mask);
413 }
414
416 bool operator>=(const bitvect& other) const
417 {
418 return !(*this < other);
419 }
420
422 bool operator>(const bitvect& other) const
423 {
424 return other < *this;
425 }
426
428 bool operator<=(const bitvect& other) const
429 {
430 return !(other < *this);
431 }
432
434 template<typename F>
435 void foreach_set_index(F callback) const
436 {
437 const size_t bpb = 8 * sizeof(bitvect::block_t);
438 size_t rest = size() % bpb;
439 for (size_t i = 0; i <= block_count_ - 1; ++i)
440 {
441 block_t b = storage_[i];
442 if ((i == block_count_ - 1) && rest)
443 // The last block might not be fully used, scan only the
444 // relevant portion.
445 b &= (1UL << rest) - 1;
446 if (b != 0)
447 {
448 unsigned base = i * bpb;
449#if __GNUC__
450 // This version is probably faster on sparse bitsets.
451 do
452 {
453 unsigned bit = __builtin_ctzl(b);
454 b ^= 1UL << bit;
455 callback(base + bit);
456 }
457 while (b);
458#else
459 unsigned bit = 0;
460 do
461 {
462 if (b & 1)
463 callback(base + bit);
464 ++bit;
465 b >>= 1;
466 }
467 while (b);
468#endif
469 }
470 }
471 }
472
473 friend SPOT_API bitvect* make_bitvect(size_t bitcount);
474
476 friend SPOT_API std::ostream& operator<<(std::ostream&,
477 const bitvect&);
478
479 private:
480 friend SPOT_API bitvect_array* make_bitvect_array(size_t bitcount,
481 size_t vectcount);
482
483 size_t size_;
484 size_t block_count_;
485 // storage_ points to local_storage_ as long as size_ <= block_count_ * 8.
486 block_t* storage_;
487 // Keep this at the end of the structure: when make_bitvect is used,
488 // it may allocate more block_t at the end of this structure.
489 block_t local_storage_;
490 };
491
493 class SPOT_API bitvect_array
494 {
495 private:
497 bitvect_array(size_t size, size_t bvsize):
498 size_(size),
499 bvsize_(bvsize)
500 {
501 }
502
503 SPOT_LOCAL bitvect_array(const bitvect_array&) = delete;
504 SPOT_LOCAL void operator=(const bitvect_array&) = delete;
505
506 // Extra storage has been allocated at the end of the struct.
507 char* storage()
508 {
509 return reinterpret_cast<char*>(this) + sizeof(*this);
510 }
511
512 const char* storage() const
513 {
514 return reinterpret_cast<const char*>(this) + sizeof(*this);
515 }
516
517 public:
519 {
520 for (size_t i = 0; i < size_; ++i)
521 at(i).~bitvect();
522 }
523
525 void operator delete(void *ptr)
526 {
527 // This object was allocated using a placement new.
528 ::operator delete(ptr);
529 }
530
532 size_t size() const
533 {
534 return size_;
535 }
536
539 {
540 // FIXME: This could be changed into a large memset if the
541 // individual vectors where not allowed to be reallocated.
542 for (unsigned s = 0; s < size_; s++)
543 at(s).clear_all();
544 }
545
547 bitvect& at(const size_t index)
548 {
549 SPOT_ASSERT(index < size_);
550 // The double cast is to prevent -Wcast-align diagnostics
551 // about the fact that char* (the type of storage) has a
552 // smaller required alignment than bitvect*.
553 auto v = static_cast<void*>(storage() + index * bvsize_);
554 return *static_cast<bitvect*>(v);
555 }
556
558 const bitvect& at(const size_t index) const
559 {
560 SPOT_ASSERT(index < size_);
561 auto v = static_cast<const void*>(storage() + index * bvsize_);
562 return *static_cast<const bitvect*>(v);
563 }
564
565 friend SPOT_API bitvect_array* make_bitvect_array(size_t bitcount,
566 size_t vectcount);
567
568
570 friend SPOT_API std::ostream& operator<<(std::ostream&,
571 const bitvect_array&);
572
573 private:
574 size_t size_;
575 size_t bvsize_;
576 };
577
579}
An array of fixed-size bit vectors allocated contiguously.
Definition bitvect.hh:494
friend bitvect_array * make_bitvect_array(size_t bitcount, size_t vectcount)
Allocate vectcount bit-vectors of bitcount bits.
const bitvect & at(const size_t index) const
Return the bit-vector at index.
Definition bitvect.hh:558
void clear_all()
Clear all bits in all vectors of the array.
Definition bitvect.hh:538
friend std::ostream & operator<<(std::ostream &, const bitvect_array &)
Print a bitvect_array.
bitvect & at(const size_t index)
Return the bit-vector at index.
Definition bitvect.hh:547
size_t size() const
The number of bitvect in the array.
Definition bitvect.hh:532
A bit vector.
Definition bitvect.hh:51
friend bitvect_array * make_bitvect_array(size_t bitcount, size_t vectcount)
Allocate vectcount bit-vectors of bitcount bits.
bitvect & add_common(const bitvect &other1, const bitvect &other2)
OR into *this the bits common to other1 and other2.
Definition bitvect.hh:277
bitvect & operator|=(const bitvect &other)
In-place bitwise OR with other.
Definition bitvect.hh:257
bool operator<=(const bitvect &other) const
Lexicographic less-than-or-equal comparison.
Definition bitvect.hh:428
void reserve_blocks(size_t new_block_count)
Definition bitvect.hh:111
bool is_fully_set() const
Return true iff all bits are set to one.
Definition bitvect.hh:201
bitvect & operator^=(const bitvect &other)
In-place bitwise XOR with other.
Definition bitvect.hh:299
void set(size_t pos)
Set bit at position pos to one.
Definition bitvect.hh:232
bitvect & operator-=(const bitvect &other)
Clear in *this the bits that are set in other.
Definition bitvect.hh:309
bool is_fully_clear() const
Return true iff all bits are zero.
Definition bitvect.hh:184
bool intersects(const bitvect &other)
Return true if *this and other share any set bit.
Definition bitvect.hh:288
void make_empty()
Reset the size to zero without freeing storage.
Definition bitvect.hh:87
friend bitvect * make_bitvect(size_t bitcount)
Allocate a bit-vector of bitcount bits.
bool operator==(const bitvect &other) const
Equality comparison.
Definition bitvect.hh:366
friend std::ostream & operator<<(std::ostream &, const bitvect &)
Print a bitvect.
bitvect & operator&=(const bitvect &other)
In-place bitwise AND with other.
Definition bitvect.hh:267
unsigned long block_t
Storage block type.
Definition bitvect.hh:58
bool is_subset_of(const bitvect &other) const
Return true if every set bit of *this is also set in other.
Definition bitvect.hh:318
void set_all()
Set all bits to one.
Definition bitvect.hh:218
bool operator>(const bitvect &other) const
Lexicographic greater-than comparison.
Definition bitvect.hh:422
void foreach_set_index(F callback) const
Call callback with the index of each set bit.
Definition bitvect.hh:435
size_t hash() const noexcept
Return a hash of the bit vector.
size_t capacity() const
Return the maximum number of bits the storage can hold.
Definition bitvect.hh:160
bitvect * clone() const
Return a heap-allocated copy.
void clear(size_t pos)
Clear bit at position pos (set it to zero).
Definition bitvect.hh:240
size_t size() const
Return the number of bits in the vector.
Definition bitvect.hh:154
size_t used_blocks() const
Return the number of blocks currently in use.
Definition bitvect.hh:147
void clear_all()
Clear all bits (set them to zero).
Definition bitvect.hh:177
void flip(size_t pos)
Flip the bit at position pos.
Definition bitvect.hh:248
bool operator>=(const bitvect &other) const
Lexicographic greater-than-or-equal comparison.
Definition bitvect.hh:416
bool operator!=(const bitvect &other) const
Inequality comparison.
Definition bitvect.hh:388
bitvect(const bitvect &other)
Copy constructor.
Definition bitvect.hh:69
unsigned count() const
Return the number of set bits (popcount).
Definition bitvect.hh:339
bitvect & operator=(const bitvect &other)
Copy-assignment operator.
Definition bitvect.hh:93
void flip_all()
Flip all bits.
Definition bitvect.hh:225
bool operator<(const bitvect &other) const
Lexicographic less-than comparison.
Definition bitvect.hh:394
Definition automata.hh:26
bitvect * make_bitvect(size_t bitcount)
Allocate a bit-vector of bitcount bits.
bitvect_array * make_bitvect_array(size_t bitcount, size_t vectcount)
Allocate vectcount bit-vectors of bitcount bits.

Please direct any question, comment, or bug report to the Spot mailing list at spot@lrde.epita.fr.
Generated on Fri Feb 27 2015 10:00:07 for spot by doxygen 1.9.8