spot  2.16
bitset.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 <array>
22 #include <spot/misc/hashfunc.hh>
23 #include <spot/misc/common.hh>
24 #include <spot/misc/clz.hh>
25 
26 namespace spot
27 {
28 #ifndef SWIG
29  namespace internal
30  {
31  [[noreturn]] SPOT_API void report_bit_shift_too_big();
32  [[noreturn]] SPOT_API void report_bit_out_of_bounds();
33  }
34 #endif
35 
38  template<size_t N>
39  class SPOT_API bitset
40  {
41  using word_t = unsigned;
42  // the number of bits must hold on an unsigned
43  static_assert(8*N*sizeof(word_t) < -1U, "too many bits in bitset");
44 
45  std::array<word_t, N> data;
46 
48  struct minus_one_tag {};
49  explicit bitset(minus_one_tag)
50  {
51  for (auto& v : data)
52  v = -1U;
53  }
54 
55  constexpr explicit bitset(word_t s)
56  : data{{s}}
57  {
58  SPOT_ASSERT(s == 0U || s == 1U);
59  }
60 
61  public:
62  // constructor
63  bitset() = default;
64  ~bitset() = default;
65 
67  static constexpr bitset zero() { return bitset{0U}; }
69  static constexpr bitset one() { return bitset{1U}; }
71  static bitset mone() { return bitset(minus_one_tag{}); }
72 
74  explicit operator bool() const
75  {
76  for (const auto& v : data)
77  if (v)
78  return true;
79  return false;
80  }
81 
83  size_t hash() const
84  {
85  return fnv_hash(data.begin(), data.end());
86  }
87 
89  bool operator==(const bitset& other) const
90  {
91  // TODO use std::algorithms instead?
92  for (unsigned i = 0; i != N; ++i)
93  if (data[i] != other.data[i])
94  return false;
95  return true;
96  }
97 
99  bool operator!=(const bitset& other) const
100  {
101  return !this->operator==(other);
102  }
103 
105  bool operator<(const bitset& other) const
106  {
107  for (unsigned i = 0; i != N; ++i)
108  if (data[i] < other.data[i])
109  return true;
110  else if (data[i] > other.data[i])
111  return false;
112  return false;
113  }
114 
116  bool operator<=(const bitset& other) const
117  {
118  for (unsigned i = 0; i != N; ++i)
119  if (data[i] < other.data[i])
120  return true;
121  else if (data[i] > other.data[i])
122  return false;
123  return true;
124  }
125 
127  bool operator>(const bitset& other) const
128  {
129  return other.operator<(*this);
130  }
131 
133  bool operator>=(const bitset& other) const
134  {
135  return other.operator<=(*this);
136  }
137 
139  void set(unsigned s)
140  {
141 #if SPOT_DEBUG || defined(SWIGPYTHON)
142  if (SPOT_UNLIKELY(s >= 8 * N * sizeof(word_t)))
143  internal::report_bit_out_of_bounds();
144 #else
145  SPOT_ASSUME(s < 8 * N * sizeof(word_t));
146 #endif
147  data[s / (8*sizeof(word_t))] |= 1U << (s % (8*sizeof(word_t)));
148  }
149 
151  void clear(unsigned s)
152  {
153 #if SPOT_DEBUG || defined(SWIGPYTHON)
154  if (SPOT_UNLIKELY(s >= 8 * N * sizeof(word_t)))
155  internal::report_bit_out_of_bounds();
156 #else
157  SPOT_ASSUME(s < 8 * N * sizeof(word_t));
158 #endif
159  data[s / (8*sizeof(word_t))] &= ~(1U << (s % (8*sizeof(word_t))));
160  }
161 
163  bitset operator<<(unsigned s) const
164  {
165  bitset r = *this;
166  r <<= s;
167  return r;
168  }
170  bitset operator>>(unsigned s) const
171  {
172  bitset r = *this;
173  r >>= s;
174  return r;
175  }
176 
178  bitset& operator<<=(unsigned s)
179  {
180 #if SPOT_DEBUG || defined(SWIGPYTHON)
181  if (SPOT_UNLIKELY(s >= 8 * N * sizeof(word_t)))
182  internal::report_bit_shift_too_big();
183 #else
184  SPOT_ASSUME(s < 8 * N * sizeof(word_t));
185 #endif
186 
187  // Skip the rest of this function in the most common case of
188  // N==1. g++ 6 can optimize away all the loops if N==1, but
189  // clang++4 cannot and needs help.
190  if (N == 1)
191  {
192  data[0] <<= s;
193  return *this;
194  }
195 
196  if (s == 0)
197  return *this;
198  const unsigned wshift = s / (8 * sizeof(word_t));
199  const unsigned offset = s % (8 * sizeof(word_t));
200 
201  if (offset == 0)
202  {
203  for (unsigned i = N - 1; i >= wshift; --i)
204  data[i] = data[i - wshift];
205  }
206  else
207  {
208  const unsigned sub_offset = 8 * sizeof(word_t) - offset;
209  for (unsigned i = N - 1; i > wshift; --i)
210  data[i] = ((data[i - wshift] << offset) |
211  (data[i - wshift - 1] >> sub_offset));
212  data[wshift] = data[0] << offset;
213  }
214  std::fill(data.begin(), data.begin() + wshift, word_t(0));
215  return *this;
216  }
217 
219  bitset& operator>>=(unsigned s)
220  {
221 #if SPOT_DEBUG || defined(SWIGPYTHON)
222  if (SPOT_UNLIKELY(s >= 8 * N * sizeof(word_t)))
223  internal::report_bit_shift_too_big();
224 #else
225  SPOT_ASSUME(s < 8 * N * sizeof(word_t));
226 #endif
227  // Skip the rest of this function in the most common case of
228  // N==1. g++ 6 can optimize away all the loops if N==1, but
229  // clang++4 cannot and needs help.
230  if (N == 1)
231  {
232  data[0] >>= s;
233  return *this;
234  }
235 
236  if (s == 0)
237  return *this;
238  const unsigned wshift = s / (8 * sizeof(word_t));
239  const unsigned offset = s % (8 * sizeof(word_t));
240  const unsigned limit = N - wshift - 1;
241 
242  if (offset == 0)
243  {
244  for (unsigned i = 0; i <= limit; ++i)
245  data[i] = data[i + wshift];
246  }
247  else
248  {
249  const unsigned sub_offset = 8 * sizeof(word_t) - offset;
250  for (unsigned i = 0; i < limit; ++i)
251  data[i] = ((data[i + wshift] >> offset) |
252  (data[i + wshift + 1] << sub_offset));
253  data[limit] = data[N - 1] >> offset;
254  }
255  std::fill(data.begin() + limit + 1, data.end(), word_t(0));
256  return *this;
257  }
258 
261  {
262  bitset r = *this;
263  for (auto& v : r.data)
264  v = ~v;
265  return r;
266  }
267 
269  bitset operator&(const bitset& other) const
270  {
271  bitset r = *this;
272  r &= other;
273  return r;
274  }
275 
277  bitset operator|(const bitset& other) const
278  {
279  bitset r = *this;
280  r |= other;
281  return r;
282  }
283 
285  bitset operator^(const bitset& other) const
286  {
287  bitset r = *this;
288  r ^= other;
289  return r;
290  }
291 
293  bitset& operator&=(const bitset& other)
294  {
295  for (unsigned i = 0; i != N; ++i)
296  data[i] &= other.data[i];
297  return *this;
298  }
300  bitset& operator|=(const bitset& other)
301  {
302  for (unsigned i = 0; i != N; ++i)
303  data[i] |= other.data[i];
304  return *this;
305  }
307  bitset& operator^=(const bitset& other)
308  {
309  for (unsigned i = 0; i != N; ++i)
310  data[i] ^= other.data[i];
311  return *this;
312  }
313 
315  bitset operator-(word_t s) const
316  {
317  bitset r = *this;
318  r -= s;
319  return r;
320  }
322  bitset& operator-=(word_t s)
323  {
324  for (auto& v : data)
325  if (v >= s)
326  {
327  v -= s;
328  s = 0;
329  break;
330  }
331  else
332  {
333  v -= s;
334  s = 1;
335  }
336  return *this;
337  }
338 
341  {
342  bitset res = *this;
343  unsigned carry = 1;
344  for (auto& v : res.data)
345  {
346  word_t old = v;
347  v = ~v + carry;
348  carry = old == 0;
349  }
350  return res;
351  }
352 
354  unsigned count() const
355  {
356  unsigned c = 0U;
357  for (auto v : data)
358  {
359 #ifdef __GNUC__
360  c += __builtin_popcount(v);
361 #else
362  while (v)
363  {
364  ++c;
365  v &= v - 1;
366  }
367 #endif
368  }
369  return c;
370  }
371 
373  unsigned highest() const
374  {
375  unsigned res = (N-1)*8*sizeof(word_t);
376  unsigned i = N;
377  while (i--)
378  {
379  auto v = data[i];
380  if (v == 0)
381  {
382  res -= CHAR_BIT*sizeof(word_t);
383  continue;
384  }
385  return res + CHAR_BIT*sizeof(word_t) - clz(v) - 1;
386  }
387  return 0;
388  }
389 
391  unsigned lowest() const
392  {
393  unsigned res = 0U;
394  for (auto v: data)
395  {
396  if (v == 0)
397  {
398  res += 8*sizeof(v);
399  continue;
400  }
401 #ifdef __GNUC__
402  res += __builtin_ctz(v);
403 #else
404  while ((v & 1) == 0)
405  {
406  ++res;
407  v >>= 1;
408  }
409 #endif
410  return res;
411  }
412  return 0;
413  }
414  };
415 
416 }
417 
418 namespace std
419 {
421  template<size_t N>
422  struct hash<spot::bitset<N>>
423  {
425  size_t operator()(const spot::bitset<N>& b) const
426  {
427  return b.hash();
428  }
429  };
430 }
A fixed-size bitset backed by N unsigned words.
Definition: bitset.hh:40
static bitset mone()
the -1 (all bits are set to 1)
Definition: bitset.hh:71
size_t hash() const
Return a hash of the bitset.
Definition: bitset.hh:83
bitset operator|(const bitset &other) const
Return the bitwise OR of *this and other.
Definition: bitset.hh:277
bool operator<(const bitset &other) const
Lexicographic less-than comparison.
Definition: bitset.hh:105
bitset operator>>(unsigned s) const
Return the bitset shifted right by s positions.
Definition: bitset.hh:170
bool operator!=(const bitset &other) const
Inequality comparison.
Definition: bitset.hh:99
void set(unsigned s)
Set bit s to one.
Definition: bitset.hh:139
static constexpr bitset zero()
the 0
Definition: bitset.hh:67
bitset operator-(word_t s) const
Return the result of subtracting s from the bitset.
Definition: bitset.hh:315
unsigned highest() const
Return the position of the highest set bit.
Definition: bitset.hh:373
bitset & operator|=(const bitset &other)
In-place bitwise OR with other.
Definition: bitset.hh:300
bool operator>(const bitset &other) const
Lexicographic greater-than comparison.
Definition: bitset.hh:127
bool operator==(const bitset &other) const
Equality comparison.
Definition: bitset.hh:89
unsigned count() const
Return the number of set bits (popcount).
Definition: bitset.hh:354
bool operator<=(const bitset &other) const
Lexicographic less-than-or-equal comparison.
Definition: bitset.hh:116
bitset operator-() const
Return the arithmetic negation (two's complement).
Definition: bitset.hh:340
bool operator>=(const bitset &other) const
Lexicographic greater-than-or-equal comparison.
Definition: bitset.hh:133
bitset operator&(const bitset &other) const
Return the bitwise AND of *this and other.
Definition: bitset.hh:269
bitset operator^(const bitset &other) const
Return the bitwise XOR of *this and other.
Definition: bitset.hh:285
bitset operator<<(unsigned s) const
Return the bitset shifted left by s positions.
Definition: bitset.hh:163
bitset & operator&=(const bitset &other)
In-place bitwise AND with other.
Definition: bitset.hh:293
static constexpr bitset one()
the 1
Definition: bitset.hh:69
unsigned lowest() const
Return the position of the lowest set bit.
Definition: bitset.hh:391
bitset & operator-=(word_t s)
Subtract s from the bitset in place.
Definition: bitset.hh:322
bitset & operator>>=(unsigned s)
Shift right in place by s positions.
Definition: bitset.hh:219
bitset & operator<<=(unsigned s)
Shift left in place by s positions.
Definition: bitset.hh:178
bitset & operator^=(const bitset &other)
In-place bitwise XOR with other.
Definition: bitset.hh:307
void clear(unsigned s)
Clear bit s (set it to zero).
Definition: bitset.hh:151
bitset operator~() const
Return the bitwise complement.
Definition: bitset.hh:260
size_t fnv_hash(It begin, It end)
Fowler-Noll-Vo hash function.
Definition: hashfunc.hh:95
constexpr unsigned clz(Type n) noexcept
Count leading zeros of an unsigned integer.
Definition: clz.hh:31
@ U
until
Definition: automata.hh:26
constexpr bool operator==(trival a, trival b)
Equality comparison of two trival values.
Definition: trival.hh:134
size_t operator()(const spot::bitset< N > &b) const
Compute the hash of b.
Definition: bitset.hh:425

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.1