spot  1.2.6
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
bitvect.hh
1 // -*- coding: utf-8 -*-
2 // Copyright (C) 2013, 2014 Laboratoire de Recherche et Développement
3 // de l'Epita (LRDE).
4 //
5 // This file is part of Spot, a model checking library.
6 //
7 // Spot is free software; you can redistribute it and/or modify it
8 // under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // Spot is distributed in the hope that it will be useful, but WITHOUT
13 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 // License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 
20 #ifndef SPOT_MISC_BITVECT_HH
21 # define SPOT_MISC_BITVECT_HH
22 
23 # include "common.hh"
24 # include <cstddef>
25 # include <cstdlib>
26 # include <cassert>
27 # include <iosfwd>
28 # include <iostream>
29 # include <algorithm>
30 
31 namespace spot
32 {
35 
36  class bitvect;
37  class bitvect_array;
38 
42  SPOT_API bitvect* make_bitvect(size_t bitcount);
43 
47  SPOT_API bitvect_array* make_bitvect_array(size_t bitcount,
48  size_t vectcount);
49 
51  class SPOT_API bitvect
52  {
53  private:
54  // Used by make_bitvect to construct a large bitvect in place.
55  bitvect(size_t size, size_t block_count);
56  bitvect(size_t size, size_t block_count, bool);
57 
58  public:
59  typedef unsigned long block_t;
60 
61  bitvect():
62  size_(0),
63  block_count_(1),
64  storage_(&local_storage_),
65  local_storage_(0)
66  {
67  }
68 
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 
79  void make_empty()
80  {
81  size_ = 0;
82  }
83 
84  bitvect& operator=(const bitvect& other)
85  {
86  reserve_blocks(other.block_count_);
87  size_ = other.size();
88  for (size_t i = 0; i < block_count_; ++i)
89  storage_[i] = other.storage_[i];
90  return *this;
91  }
92 
93  ~bitvect()
94  {
95  if (storage_ != &local_storage_)
96  free(storage_);
97  }
98 
102  void reserve_blocks(size_t new_block_count)
103  {
104  if (new_block_count < block_count_)
105  return;
106  if (storage_ == &local_storage_)
107  {
108  block_t* new_storage_ = static_cast<block_t*>
109  (malloc(new_block_count * sizeof(block_t)));
110  for (size_t i = 0; i < block_count_; ++i)
111  new_storage_[i] = storage_[i];
112  storage_ = new_storage_;
113  }
114  else
115  {
116  storage_ = static_cast<block_t*>
117  (realloc(storage_, new_block_count * sizeof(block_t)));
118  }
119  block_count_ = new_block_count;
120  }
121 
122  private:
123  void grow()
124  {
125  size_t new_block_count_ = (block_count_ + 1) * 7 / 5;
126  reserve_blocks(new_block_count_);
127  }
128 
129  public:
130 
131  size_t used_blocks() const
132  {
133  const size_t bpb = 8 * sizeof(block_t);
134  return (size_ + bpb - 1) / bpb;
135  }
136 
138  void push_back(bool val)
139  {
140  if (size() == capacity())
141  grow();
142  size_t pos = size_++;
143  if (val)
144  set(pos);
145  else
146  clear(pos);
147  }
148 
150  void push_back(block_t data, unsigned count)
151  {
152  if (size() + count > capacity())
153  grow();
154  const size_t bpb = 8 * sizeof(block_t);
155 
156  // Clear the higher bits.
157  if (count != bpb)
158  data &= (1UL << count) - 1;
159 
160  size_t n = size() % bpb;
161  size_t i = size_ / bpb;
162  size_ += count;
163  if (n == 0) // Aligned on block_t boundary
164  {
165  storage_[i] = data;
166  }
167  else // Only (bpb-n) bits free in this block.
168  {
169  // Take the lower bpb-n bits of data...
170  block_t mask = (1UL << (bpb - n)) - 1;
171  block_t data1 = (data & mask) << n;
172  mask <<= n;
173  // ... write them on the higher bpb-n bits of last block.
174  storage_[i] = (storage_[i] & ~mask) | data1;
175  // Write the remaining bits in the next block.
176  if (bpb - n < count)
177  storage_[i + 1] = data >> (bpb - n);
178  }
179  }
180 
181  size_t size() const
182  {
183  return size_;
184  }
185 
186  size_t capacity() const
187  {
188  return 8 * block_count_ * sizeof(block_t);
189  }
190 
191  size_t hash() const;
192 
193  bool get(size_t pos) const
194  {
195  assert(pos < size_);
196  const size_t bpb = 8 * sizeof(block_t);
197  return storage_[pos / bpb] & (1UL << (pos % bpb));
198  }
199 
200  void clear_all()
201  {
202  for (size_t i = 0; i < block_count_; ++i)
203  storage_[i] = 0;
204  }
205 
206  bool is_fully_clear() const
207  {
208  size_t i;
209  for (i = 0; i < block_count_ - 1; ++i)
210  if (storage_[i] != 0)
211  return false;
212  // The last block might not be fully used, compare only the
213  // relevant portion.
214  const size_t bpb = 8 * sizeof(bitvect::block_t);
215  block_t mask = (1UL << (size() % bpb)) - 1;
216  return (storage_[i] & mask) == 0;
217  }
218 
219  bool is_fully_set() const
220  {
221  size_t i;
222  for (i = 0; i < block_count_ - 1; ++i)
223  if (storage_[i] != -1UL)
224  return false;
225  // The last block might not be fully used, compare only the
226  // relevant portion.
227  const size_t bpb = 8 * sizeof(bitvect::block_t);
228  block_t mask = (1UL << (size() % bpb)) - 1;
229  return ((~storage_[i]) & mask) == 0;
230  }
231 
232  void set_all()
233  {
234  for (size_t i = 0; i < block_count_; ++i)
235  storage_[i] = -1UL;
236  }
237 
238  void flip_all()
239  {
240  for (size_t i = 0; i < block_count_; ++i)
241  storage_[i] = ~storage_[i];
242  }
243 
244  void set(size_t pos)
245  {
246  assert(pos < size_);
247  const size_t bpb = 8 * sizeof(block_t);
248  storage_[pos / bpb] |= 1UL << (pos % bpb);
249  }
250 
251  void clear(size_t pos)
252  {
253  assert(pos < size_);
254  const size_t bpb = 8 * sizeof(block_t);
255  storage_[pos / bpb] &= ~(1UL << (pos % bpb));
256  }
257 
258  void flip(size_t pos)
259  {
260  assert(pos < size_);
261  const size_t bpb = 8 * sizeof(block_t);
262  storage_[pos / bpb] ^= (1UL << (pos % bpb));
263  }
264 
265 
266  bitvect& operator|=(const bitvect& other)
267  {
268  assert(other.size_ <= size_);
269  unsigned m = std::min(other.block_count_, block_count_);
270  for (size_t i = 0; i < m; ++i)
271  storage_[i] |= other.storage_[i];
272  return *this;
273  }
274 
275  bitvect& operator&=(const bitvect& other)
276  {
277  assert(other.size_ <= size_);
278  unsigned m = std::min(other.block_count_, block_count_);
279  for (size_t i = 0; i < m; ++i)
280  storage_[i] &= other.storage_[i];
281  return *this;
282  }
283 
284  bitvect& operator^=(const bitvect& other)
285  {
286  assert(other.size_ <= size_);
287  unsigned m = std::min(other.block_count_, block_count_);
288  for (size_t i = 0; i < m; ++i)
289  storage_[i] ^= other.storage_[i];
290  return *this;
291  }
292 
293  bitvect& operator-=(const bitvect& other)
294  {
295  assert(other.block_count_ <= block_count_);
296  for (size_t i = 0; i < other.block_count_; ++i)
297  storage_[i] &= ~other.storage_[i];
298  return *this;
299  }
300 
301  bool operator==(const bitvect& other) const
302  {
303  if (other.size_ != size_)
304  return false;
305  if (size_ == 0)
306  return true;
307  size_t i;
308  size_t m = other.used_blocks();
309  for (i = 0; i < m - 1; ++i)
310  if (storage_[i] != other.storage_[i])
311  return false;
312  // The last block might not be fully used, compare only the
313  // relevant portion.
314  const size_t bpb = 8 * sizeof(bitvect::block_t);
315  block_t mask = (1UL << (size() % bpb)) - 1;
316  return (storage_[i] & mask) == (other.storage_[i] & mask);
317  }
318 
319  bool operator!=(const bitvect& other) const
320  {
321  return !(*this == other);
322  }
323 
324  bool operator<(const bitvect& other) const
325  {
326  if (size_ != other.size_)
327  return size_ < other.size_;
328  if (size_ == 0)
329  return false;
330  size_t i;
331  size_t m = other.used_blocks();
332  for (i = 0; i < m - 1; ++i)
333  if (storage_[i] > other.storage_[i])
334  return false;
335  // The last block might not be fully used, compare only the
336  // relevant portion.
337  const size_t bpb = 8 * sizeof(bitvect::block_t);
338  block_t mask = (1UL << (size() % bpb)) - 1;
339  return (storage_[i] & mask) < (other.storage_[i] & mask);
340  }
341 
342  bool operator>=(const bitvect& other) const
343  {
344  return !(*this < other);
345  }
346 
347  bool operator>(const bitvect& other) const
348  {
349  return other < *this;
350  }
351 
352  bool operator<=(const bitvect& other) const
353  {
354  return !(other < *this);
355  }
356 
357  // \brief Extract a range of bits.
358  //
359  // Build a new bit-vector using the bits from \a begin (included)
360  // to \a end (excluded).
361  bitvect* extract_range(size_t begin, size_t end)
362  {
363  assert(begin <= end);
364  assert(end <= size());
365  size_t count = end - begin;
366  bitvect* res = make_bitvect(count);
367  res->make_empty();
368 
369  if (end == begin)
370  return res;
371 
372  const size_t bpb = 8 * sizeof(bitvect::block_t);
373 
374  size_t indexb = begin / bpb;
375  unsigned bitb = begin % bpb;
376  size_t indexe = (end - 1) / bpb;
377 
378  if (indexb == indexe)
379  {
380  block_t data = storage_[indexb];
381  data >>= bitb;
382  res->push_back(data, count);
383  }
384  else
385  {
386  block_t data = storage_[indexb];
387  data >>= bitb;
388  res->push_back(data, bpb - bitb);
389  count -= bpb - bitb;
390  while (count >= bpb)
391  {
392  ++indexb;
393  res->push_back(storage_[indexb], bpb);
394  count -= bpb;
395  assert(indexb != indexe || count == 0);
396  }
397  if (count > 0)
398  {
399  ++indexb;
400  assert(indexb == indexe);
401  assert(count == end % bpb);
402  res->push_back(storage_[indexb], count);
403  }
404  }
405  return res;
406  }
407 
408  friend SPOT_API bitvect*
409  ::spot::make_bitvect(size_t bitcount);
410 
412  friend SPOT_API std::ostream& operator<<(std::ostream&,
413  const bitvect&);
414 
415  private:
416  friend SPOT_API bitvect_array*
417  ::spot::make_bitvect_array(size_t bitcount,
418  size_t vectcount);
419 
420  size_t size_;
421  size_t block_count_;
422  // storage_ points to local_storage_ as long as size_ <= block_count_ * 8.
423  block_t* storage_;
424  // Keep this at the end of the structure: when make_bitvect is used,
425  // it may allocate more block_t at the end of this structure.
426  block_t local_storage_;
427  };
428 
429  class SPOT_API bitvect_array
430  {
431  private:
433  bitvect_array(size_t size, size_t bvsize):
434  size_(size),
435  bvsize_(bvsize)
436  {
437  }
438 
440  SPOT_LOCAL bitvect_array(const bitvect_array&);
442  SPOT_LOCAL void operator=(const bitvect_array&);
443 
444 
445  public:
446  ~bitvect_array()
447  {
448  for (size_t i = 0; i < size_; ++i)
449  at(i).~bitvect();
450  }
451 
453  size_t size() const
454  {
455  return size_;
456  }
457 
459  bitvect& at(const size_t index)
460  {
461  assert(index < size_);
462  return *reinterpret_cast<bitvect*>(storage_ + index * bvsize_);
463  }
464 
466  const bitvect& at(const size_t index) const
467  {
468  assert(index < size_);
469  return *reinterpret_cast<const bitvect*>(storage_ + index * bvsize_);
470  }
471 
472  friend SPOT_API bitvect_array*
473  ::spot::make_bitvect_array(size_t bitcount,
474  size_t vectcount);
475 
476 
478  friend SPOT_API std::ostream& operator<<(std::ostream&,
479  const bitvect_array&);
480 
481  private:
482  size_t size_;
483  size_t bvsize_;
484  char storage_[0];
485  };
486 
488 }
489 
490 
491 #endif // SPOT_MISC_BITVECT_HH

Please direct any question, comment, or bug report to the Spot mailing list at spot@lrde.epita.fr.
Generated on Sat Dec 6 2014 12:28:43 for spot by doxygen 1.8.4