CBMC
irep.h
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module:
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
9 
10 #ifndef CPROVER_UTIL_IREP_H
11 #define CPROVER_UTIL_IREP_H
12 
13 #include <string>
14 #include <vector>
15 
16 #include "invariant.h"
17 #include "irep_ids.h"
18 
19 #define SHARING
20 #ifndef HASH_CODE
21 # define HASH_CODE 1
22 #endif
23 // use forward_list by default, unless _GLIBCXX_DEBUG is set as the debug
24 // overhead is noticeably higher with the regression test suite taking four
25 // times as long.
26 #if !defined(NAMED_SUB_IS_FORWARD_LIST) && !defined(_GLIBCXX_DEBUG)
27 # define NAMED_SUB_IS_FORWARD_LIST 1
28 #endif
29 
30 #if NAMED_SUB_IS_FORWARD_LIST
31 # include "forward_list_as_map.h"
32 #else
33 #include <map>
34 #endif
35 
37 // NOLINTNEXTLINE(readability/identifiers)
39 
40 inline const std::string &id2string(const irep_idt &d)
41 {
42  return as_string(d);
43 }
44 
45 #ifdef IREP_DEBUG
46 #include <iostream>
47 #endif
48 
49 class irept;
50 const irept &get_nil_irep();
51 
55 template <bool enabled>
57 {
58 };
59 
60 template <>
61 struct ref_count_ift<true>
62 {
63  unsigned ref_count = 1;
64 };
65 
84 template <typename treet, typename named_subtreest, bool sharing = true>
85 class tree_nodet : public ref_count_ift<sharing>
86 {
87 public:
88  // These are not stable.
89  typedef std::vector<treet> subt;
90 
91  // named_subt has to provide stable references; we can
92  // use std::forward_list or std::vector< unique_ptr<T> > to save
93  // memory and increase efficiency.
94  using named_subt = named_subtreest;
95 
96  friend treet;
97 
100 
103 
104 #if HASH_CODE
105  mutable std::size_t hash_code = 0;
106 #endif
107 
108  void clear()
109  {
110  data.clear();
111  sub.clear();
112  named_sub.clear();
113 #if HASH_CODE
114  hash_code = 0;
115 #endif
116  }
117 
118  void swap(tree_nodet &d)
119  {
120  d.data.swap(data);
121  d.sub.swap(sub);
122  d.named_sub.swap(named_sub);
123 #if HASH_CODE
124  std::swap(d.hash_code, hash_code);
125 #endif
126  }
127 
128  tree_nodet() = default;
129 
130  explicit tree_nodet(irep_idt _data) : data(std::move(_data))
131  {
132  }
133 
134  tree_nodet(irep_idt _data, named_subt _named_sub, subt _sub)
135  : data(std::move(_data)),
136  named_sub(std::move(_named_sub)),
137  sub(std::move(_sub))
138  {
139  }
140 };
141 
143 template <typename derivedt, typename named_subtreest>
145 {
146 public:
148  using subt = typename dt::subt;
149  using named_subt = typename dt::named_subt;
150 
153 
154  explicit sharing_treet(irep_idt _id) : data(new dt(std::move(_id)))
155  {
156  }
157 
158  sharing_treet(irep_idt _id, named_subt _named_sub, subt _sub)
159  : data(new dt(std::move(_id), std::move(_named_sub), std::move(_sub)))
160  {
161  }
162 
163  // constructor for blank irep
165  {
166  }
167 
168  // copy constructor
169  sharing_treet(const sharing_treet &irep) : data(irep.data)
170  {
171  if(data!=&empty_d)
172  {
173  PRECONDITION(data->ref_count != 0);
174  data->ref_count++;
175 #ifdef IREP_DEBUG
176  std::cout << "COPY " << data << " " << data->ref_count << '\n';
177 #endif
178  }
179  }
180 
181  // Copy from rvalue reference.
182  // Note that this does avoid a branch compared to the
183  // standard copy constructor above.
185  {
186 #ifdef IREP_DEBUG
187  std::cout << "COPY MOVE\n";
188 #endif
189  irep.data=&empty_d;
190  }
191 
193  {
194 #ifdef IREP_DEBUG
195  std::cout << "ASSIGN\n";
196 #endif
197 
198  // Ordering is very important here!
199  // Consider self-assignment, which may destroy 'irep'
200  dt *irep_data=irep.data;
201  if(irep_data!=&empty_d)
202  irep_data->ref_count++;
203 
204  remove_ref(data); // this may kill 'irep'
205  data=irep_data;
206 
207  return *this;
208  }
209 
210  // Note that the move assignment operator does avoid
211  // three branches compared to standard operator above.
213  {
214 #ifdef IREP_DEBUG
215  std::cout << "ASSIGN MOVE\n";
216 #endif
217  // we simply swap two pointers
218  std::swap(data, irep.data);
219  return *this;
220  }
221 
223  {
224  remove_ref(data);
225  }
226 
227 protected:
229  static dt empty_d;
230 
231  static void remove_ref(dt *old_data);
232  static void nonrecursive_destructor(dt *old_data);
233  void detach();
234 
235 public:
236  const dt &read() const
237  {
238  return *data;
239  }
240 
242  {
243  detach();
244 #if HASH_CODE
245  data->hash_code = 0;
246 #endif
247  return *data;
248  }
249 };
250 
251 // Static field initialization
252 template <typename derivedt, typename named_subtreest>
255 
257 template <typename derivedt, typename named_subtreest>
259 {
260 public:
262  using subt = typename dt::subt;
263  using named_subt = typename dt::named_subt;
264 
267 
268  explicit non_sharing_treet(irep_idt _id) : data(std::move(_id))
269  {
270  }
271 
272  non_sharing_treet(irep_idt _id, named_subt _named_sub, subt _sub)
273  : data(std::move(_id), std::move(_named_sub), std::move(_sub))
274  {
275  }
276 
277  non_sharing_treet() = default;
278 
279  const dt &read() const
280  {
281  return data;
282  }
283 
285  {
286 #if HASH_CODE
287  data.hash_code = 0;
288 #endif
289  return data;
290  }
291 
292 protected:
294 };
295 
347 class irept
348 #ifdef SHARING
349  : public sharing_treet<
350  irept,
351 #else
352  : public non_sharing_treet<
353  irept,
354 #endif
355 #if NAMED_SUB_IS_FORWARD_LIST
356  forward_list_as_mapt<irep_idt, irept>>
357 #else
358  std::map<irep_idt, irept>>
359 #endif
360 {
361 public:
363 
364  bool is_nil() const
365  {
366  return id() == ID_nil;
367  }
368  bool is_not_nil() const
369  {
370  return id() != ID_nil;
371  }
372 
373  explicit irept(const irep_idt &_id) : baset(_id)
374  {
375  }
376 
377  irept(const irep_idt &_id, const named_subt &_named_sub, const subt &_sub)
378  : baset(_id, _named_sub, _sub)
379  {
380  }
381 
382  irept() = default;
383 
384  const irep_idt &id() const
385  { return read().data; }
386 
387  const std::string &id_string() const
388  { return id2string(read().data); }
389 
390  void id(const irep_idt &_data)
391  { write().data=_data; }
392 
393  const irept &find(const irep_idt &name) const;
394  irept &add(const irep_idt &name);
395  irept &add(const irep_idt &name, irept irep);
396 
397  const std::string &get_string(const irep_idt &name) const
398  {
399  return id2string(get(name));
400  }
401 
402  const irep_idt &get(const irep_idt &name) const;
403  bool get_bool(const irep_idt &name) const;
404  signed int get_int(const irep_idt &name) const;
405  std::size_t get_size_t(const irep_idt &name) const;
406  long long get_long_long(const irep_idt &name) const;
407 
408  void set(const irep_idt &name, const irep_idt &value)
409  {
410  add(name, irept(value));
411  }
412  void set(const irep_idt &name, irept irep)
413  {
414  add(name, std::move(irep));
415  }
416  void set(const irep_idt &name, const long long value);
417  void set_size_t(const irep_idt &name, const std::size_t value);
418 
419  void remove(const irep_idt &name);
420  void move_to_sub(irept &irep);
421  void move_to_named_sub(const irep_idt &name, irept &irep);
422 
423  bool operator==(const irept &other) const;
424 
425  bool operator!=(const irept &other) const
426  {
427  return !(*this==other);
428  }
429 
430  void swap(irept &irep)
431  {
432  std::swap(irep.data, data);
433  }
434 
435  bool operator<(const irept &other) const;
436  bool ordering(const irept &other) const;
437 
438  int compare(const irept &i) const;
439 
440  void clear() { *this=irept(); }
441 
442  void make_nil() { *this=get_nil_irep(); }
443 
444  subt &get_sub() { return write().sub; } // DANGEROUS
445  const subt &get_sub() const { return read().sub; }
446  named_subt &get_named_sub() { return write().named_sub; } // DANGEROUS
447  const named_subt &get_named_sub() const { return read().named_sub; }
448 
449  std::size_t hash() const;
450  std::size_t full_hash() const;
451 
452  bool full_eq(const irept &other) const;
453 
454  std::string pretty(unsigned indent=0, unsigned max_indent=0) const;
455 
456  static bool is_comment(const irep_idt &name)
457  { return !name.empty() && name[0]=='#'; }
458 
460  static std::size_t number_of_non_comments(const named_subt &);
461 };
462 
463 // NOLINTNEXTLINE(readability/identifiers)
464 struct irep_hash
465 {
466  std::size_t operator()(const irept &irep) const
467  {
468  return irep.hash();
469  }
470 };
471 
472 // NOLINTNEXTLINE(readability/identifiers)
474 {
475  std::size_t operator()(const irept &irep) const
476  {
477  return irep.full_hash();
478  }
479 };
480 
481 // NOLINTNEXTLINE(readability/identifiers)
483 {
484  bool operator()(const irept &i1, const irept &i2) const
485  {
486  return i1.full_eq(i2);
487  }
488 };
489 
491 {
492  const irept &irep;
493  explicit irep_pretty_diagnosticst(const irept &irep);
494 };
495 
496 template <>
498 {
499  static std::string diagnostics_as_string(const irep_pretty_diagnosticst &irep)
500  {
501  return irep.irep.pretty();
502  }
503 };
504 
505 template <typename derivedt, typename named_subtreest>
507 {
508 #ifdef IREP_DEBUG
509  std::cout << "DETACH1: " << data << '\n';
510 #endif
511 
512  if(data == &empty_d)
513  {
514  data = new dt;
515 
516 #ifdef IREP_DEBUG
517  std::cout << "ALLOCATED " << data << '\n';
518 #endif
519  }
520  else if(data->ref_count > 1)
521  {
522  dt *old_data(data);
523  data = new dt(*old_data);
524 
525 #ifdef IREP_DEBUG
526  std::cout << "ALLOCATED " << data << '\n';
527 #endif
528 
529  data->ref_count = 1;
530  remove_ref(old_data);
531  }
532 
533  POSTCONDITION(data->ref_count == 1);
534 
535 #ifdef IREP_DEBUG
536  std::cout << "DETACH2: " << data << '\n';
537 #endif
538 }
539 
540 template <typename derivedt, typename named_subtreest>
542 {
543  if(old_data == &empty_d)
544  return;
545 
546 #if 0
547  nonrecursive_destructor(old_data);
548 #else
549 
550  PRECONDITION(old_data->ref_count != 0);
551 
552 #ifdef IREP_DEBUG
553  std::cout << "R: " << old_data << " " << old_data->ref_count << '\n';
554 #endif
555 
556  old_data->ref_count--;
557  if(old_data->ref_count == 0)
558  {
559 #ifdef IREP_DEBUG
560  std::cout << "D: " << pretty() << '\n';
561  std::cout << "DELETING " << old_data->data << " " << old_data << '\n';
562  old_data->clear();
563  std::cout << "DEALLOCATING " << old_data << "\n";
564 #endif
565 
566  // may cause recursive call
567  delete old_data;
568 
569 #ifdef IREP_DEBUG
570  std::cout << "DONE\n";
571 #endif
572  }
573 #endif
574 }
575 
578 template <typename derivedt, typename named_subtreest>
580  dt *old_data)
581 {
582  std::vector<dt *> stack(1, old_data);
583 
584  while(!stack.empty())
585  {
586  dt *d = stack.back();
587  stack.erase(--stack.end());
588  if(d == &empty_d)
589  continue;
590 
591  INVARIANT(d->ref_count != 0, "All contents of the stack must be in use");
592  d->ref_count--;
593 
594  if(d->ref_count == 0)
595  {
596  stack.reserve(
597  stack.size() + std::distance(d->named_sub.begin(), d->named_sub.end()) +
598  d->sub.size());
599 
600  for(typename named_subt::iterator it = d->named_sub.begin();
601  it != d->named_sub.end();
602  it++)
603  {
604  stack.push_back(it->second.data);
605  it->second.data = &empty_d;
606  }
607 
608  for(typename subt::iterator it = d->sub.begin(); it != d->sub.end(); it++)
609  {
610  stack.push_back(it->data);
611  it->data = &empty_d;
612  }
613 
614  // now delete, won't do recursion
615  delete d;
616  }
617  }
618 }
619 
620 #endif // CPROVER_UTIL_IREP_H
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
void swap(dstringt &b)
Definition: dstring.h:162
bool empty() const
Definition: dstring.h:89
void clear()
Definition: dstring.h:159
There are a large number of kinds of tree structured or tree-like data in CPROVER.
Definition: irep.h:360
static std::size_t number_of_non_comments(const named_subt &)
count the number of named_sub elements that are not comments
Definition: irep.cpp:404
bool get_bool(const irep_idt &name) const
Definition: irep.cpp:57
irept()=default
bool operator==(const irept &other) const
Definition: irep.cpp:133
subt & get_sub()
Definition: irep.h:444
void set(const irep_idt &name, irept irep)
Definition: irep.h:412
std::string pretty(unsigned indent=0, unsigned max_indent=0) const
Definition: irep.cpp:482
void move_to_named_sub(const irep_idt &name, irept &irep)
Definition: irep.cpp:26
std::size_t get_size_t(const irep_idt &name) const
Definition: irep.cpp:67
bool operator!=(const irept &other) const
Definition: irep.h:425
const irept & find(const irep_idt &name) const
Definition: irep.cpp:93
bool ordering(const irept &other) const
defines ordering on the internal representation
Definition: irep.cpp:232
const subt & get_sub() const
Definition: irep.h:445
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:44
named_subt & get_named_sub()
Definition: irep.h:446
irept(const irep_idt &_id)
Definition: irep.h:373
const std::string & id_string() const
Definition: irep.h:387
void remove(const irep_idt &name)
Definition: irep.cpp:87
void set(const irep_idt &name, const irep_idt &value)
Definition: irep.h:408
const named_subt & get_named_sub() const
Definition: irep.h:447
void set_size_t(const irep_idt &name, const std::size_t value)
Definition: irep.cpp:82
irept(const irep_idt &_id, const named_subt &_named_sub, const subt &_sub)
Definition: irep.h:377
std::size_t hash() const
Definition: irep.cpp:415
int compare(const irept &i) const
defines ordering on the internal representation comments are ignored
Definition: irep.cpp:301
void clear()
Definition: irep.h:440
bool is_not_nil() const
Definition: irep.h:368
bool operator<(const irept &other) const
defines ordering on the internal representation
Definition: irep.cpp:395
const irep_idt & id() const
Definition: irep.h:384
bool full_eq(const irept &other) const
Definition: irep.cpp:192
long long get_long_long(const irep_idt &name) const
Definition: irep.cpp:72
std::size_t full_hash() const
Definition: irep.cpp:453
void make_nil()
Definition: irep.h:442
signed int get_int(const irep_idt &name) const
Definition: irep.cpp:62
static bool is_comment(const irep_idt &name)
Definition: irep.h:456
void move_to_sub(irept &irep)
Definition: irep.cpp:35
void swap(irept &irep)
Definition: irep.h:430
void id(const irep_idt &_data)
Definition: irep.h:390
const std::string & get_string(const irep_idt &name) const
Definition: irep.h:397
irept & add(const irep_idt &name)
Definition: irep.cpp:103
bool is_nil() const
Definition: irep.h:364
Base class for tree-like data structures without sharing.
Definition: irep.h:259
non_sharing_treet(irep_idt _id, named_subt _named_sub, subt _sub)
Definition: irep.h:272
non_sharing_treet()=default
typename dt::subt subt
Definition: irep.h:262
non_sharing_treet(irep_idt _id)
Definition: irep.h:268
typename dt::named_subt named_subt
Definition: irep.h:263
const dt & read() const
Definition: irep.h:279
dt & write()
Definition: irep.h:284
Base class for tree-like data structures with sharing.
Definition: irep.h:145
sharing_treet(irep_idt _id, named_subt _named_sub, subt _sub)
Definition: irep.h:158
dt & write()
Definition: irep.h:241
dt * data
Definition: irep.h:228
sharing_treet(irep_idt _id)
Definition: irep.h:154
sharing_treet & operator=(sharing_treet &&irep)
Definition: irep.h:212
static void remove_ref(dt *old_data)
Definition: irep.h:541
typename dt::named_subt named_subt
Definition: irep.h:149
typename dt::subt subt
Definition: irep.h:148
sharing_treet tree_implementationt
Used to refer to this class from derived classes.
Definition: irep.h:152
sharing_treet(const sharing_treet &irep)
Definition: irep.h:169
static void nonrecursive_destructor(dt *old_data)
Does the same as remove_ref, but using an explicit stack instead of recursion.
Definition: irep.h:579
static dt empty_d
Definition: irep.h:229
sharing_treet & operator=(const sharing_treet &irep)
Definition: irep.h:192
const dt & read() const
Definition: irep.h:236
sharing_treet()
Definition: irep.h:164
sharing_treet(sharing_treet &&irep)
Definition: irep.h:184
~sharing_treet()
Definition: irep.h:222
void detach()
Definition: irep.h:506
A node with data in a tree, it contains:
Definition: irep.h:86
named_subt named_sub
Definition: irep.h:101
named_subtreest named_subt
Definition: irep.h:94
friend treet
Definition: irep.h:96
tree_nodet()=default
void swap(tree_nodet &d)
Definition: irep.h:118
tree_nodet(irep_idt _data, named_subt _named_sub, subt _sub)
Definition: irep.h:134
std::vector< treet > subt
Definition: irep.h:89
void clear()
Definition: irep.h:108
tree_nodet(irep_idt _data)
Definition: irep.h:130
std::size_t hash_code
Definition: irep.h:105
subt sub
Definition: irep.h:102
irep_idt data
This irep_idt is the only place to store data in an tree node.
Definition: irep.h:99
dstring_hash irep_id_hash
Definition: irep.h:38
dstringt irep_idt
Definition: irep.h:36
const irept & get_nil_irep()
Definition: irep.cpp:19
#define SHARING
Definition: irep.h:19
const std::string & id2string(const irep_idt &d)
Definition: irep.h:40
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition: invariant.h:423
#define POSTCONDITION(CONDITION)
Definition: invariant.h:479
std::string as_string(const ai_verifier_statust &status)
Makes a status message string from a status.
static std::string diagnostics_as_string(const irep_pretty_diagnosticst &irep)
Definition: irep.h:499
Helper to give us some diagnostic in a usable form on assertion failure.
Definition: invariant.h:299
bool operator()(const irept &i1, const irept &i2) const
Definition: irep.h:484
std::size_t operator()(const irept &irep) const
Definition: irep.h:475
std::size_t operator()(const irept &irep) const
Definition: irep.h:466
irep_pretty_diagnosticst(const irept &irep)
Definition: irep.cpp:523
const irept & irep
Definition: irep.h:492
unsigned ref_count
Definition: irep.h:63
Used in tree_nodet for activating or not reference counting.
Definition: irep.h:57