CBMC
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
irep.h
Go to the documentation of this file.
1/*******************************************************************\
2
3Module:
4
5Author: 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#if defined(__GNUC__) && __GNUC__ >= 14
42#endif
43inline const std::string &
45{
46 return as_string(d);
47}
48
49#ifdef IREP_DEBUG
50#include <iostream>
51#endif
52
53class irept;
54const irept &get_nil_irep();
55
59template <bool enabled>
61{
62};
63
64template <>
65struct ref_count_ift<true>
66{
67 unsigned ref_count = 1;
68};
69
88template <typename treet, typename named_subtreest, bool sharing = true>
89class tree_nodet : public ref_count_ift<sharing>
90{
91public:
92 // These are not stable.
93 typedef std::vector<treet> subt;
94
95 // named_subt has to provide stable references; we can
96 // use std::forward_list or std::vector< unique_ptr<T> > to save
97 // memory and increase efficiency.
99
100 friend treet;
101
104
107
108#if HASH_CODE
109 mutable std::size_t hash_code = 0;
110#endif
111
112 void clear()
113 {
114 data.clear();
115 sub.clear();
117#if HASH_CODE
118 hash_code = 0;
119#endif
120 }
121
123 {
124 d.data.swap(data);
125 d.sub.swap(sub);
126 d.named_sub.swap(named_sub);
127#if HASH_CODE
128 std::swap(d.hash_code, hash_code);
129#endif
130 }
131
132 tree_nodet() = default;
133
134 explicit tree_nodet(irep_idt _data) : data(std::move(_data))
135 {
136 }
137
139 : data(std::move(_data)),
140 named_sub(std::move(_named_sub)),
141 sub(std::move(_sub))
142 {
143 }
144};
145
147template <typename derivedt, typename named_subtreest>
149{
150public:
152 using subt = typename dt::subt;
153 using named_subt = typename dt::named_subt;
154
157
158 explicit sharing_treet(irep_idt _id) : data(new dt(std::move(_id)))
159 {
160 }
161
163 : data(new dt(std::move(_id), std::move(_named_sub), std::move(_sub)))
164 {
165 }
166
167 // constructor for blank irep
169 {
170 }
171
172 // copy constructor
174 {
175 if(data!=&empty_d)
176 {
177 PRECONDITION(data->ref_count != 0);
178 data->ref_count++;
179#ifdef IREP_DEBUG
180 std::cout << "COPY " << data << " " << data->ref_count << '\n';
181#endif
182 }
183 }
184
185 // Copy from rvalue reference.
186 // Note that this does avoid a branch compared to the
187 // standard copy constructor above.
189 {
190#ifdef IREP_DEBUG
191 std::cout << "COPY MOVE\n";
192#endif
193 irep.data=&empty_d;
194 }
195
197 {
198#ifdef IREP_DEBUG
199 std::cout << "ASSIGN\n";
200#endif
201
202 // Ordering is very important here!
203 // Consider self-assignment, which may destroy 'irep'
204 dt *irep_data=irep.data;
205 if(irep_data!=&empty_d)
206 irep_data->ref_count++;
207
208 remove_ref(data); // this may kill 'irep'
210
211 return *this;
212 }
213
214 // Note that the move assignment operator does avoid
215 // three branches compared to standard operator above.
217 {
218#ifdef IREP_DEBUG
219 std::cout << "ASSIGN MOVE\n";
220#endif
221 // we simply swap two pointers
222 std::swap(data, irep.data);
223 return *this;
224 }
225
227 {
229 }
230
231protected:
233 static dt empty_d;
234
235 static void remove_ref(dt *old_data);
237 void detach();
238
239public:
240 const dt &read() const
241 {
242 return *data;
243 }
244
246 {
247 detach();
248#if HASH_CODE
249 data->hash_code = 0;
250#endif
251 return *data;
252 }
253};
254
255// Static field initialization
256template <typename derivedt, typename named_subtreest>
259
261template <typename derivedt, typename named_subtreest>
263{
264public:
266 using subt = typename dt::subt;
267 using named_subt = typename dt::named_subt;
268
271
273 {
274 }
275
277 : data(std::move(_id), std::move(_named_sub), std::move(_sub))
278 {
279 }
280
281 non_sharing_treet() = default;
282
283 const dt &read() const
284 {
285 return data;
286 }
287
289 {
290#if HASH_CODE
291 data.hash_code = 0;
292#endif
293 return data;
294 }
295
296protected:
298};
299
351class irept
353 : public sharing_treet<
354 irept,
355#else
356 : public non_sharing_treet<
357 irept,
358#endif
359#if NAMED_SUB_IS_FORWARD_LIST
360 forward_list_as_mapt<irep_idt, irept>>
361#else
362 std::map<irep_idt, irept>>
363#endif
364{
365public:
367
368 bool is_nil() const
369 {
370 return id() == ID_nil;
371 }
372 bool is_not_nil() const
373 {
374 return id() != ID_nil;
375 }
376
377 explicit irept(const irep_idt &_id) : baset(_id)
378 {
379 }
380
383 {
384 }
385
386 irept() = default;
387
388 const irep_idt &id() const
389 { return read().data; }
390
391 const std::string &id_string() const
392 { return id2string(read().data); }
393
394 void id(const irep_idt &_data)
395 { write().data=_data; }
396
397 const irept &find(const irep_idt &name) const;
398 irept &add(const irep_idt &name);
399 irept &add(const irep_idt &name, irept irep);
400
401 const std::string &get_string(const irep_idt &name) const
402 {
403 return id2string(get(name));
404 }
405
406 const irep_idt &get(const irep_idt &name) const;
407 bool get_bool(const irep_idt &name) const;
408 signed int get_int(const irep_idt &name) const;
409 std::size_t get_size_t(const irep_idt &name) const;
410 long long get_long_long(const irep_idt &name) const;
411
412 void set(const irep_idt &name, const irep_idt &value)
413 {
414 add(name, irept(value));
415 }
416 void set(const irep_idt &name, irept irep)
417 {
418 add(name, std::move(irep));
419 }
420 void set(const irep_idt &name, const long long value);
421 void set_size_t(const irep_idt &name, const std::size_t value);
422
423 void remove(const irep_idt &name);
424 void move_to_sub(irept &irep);
425 void move_to_named_sub(const irep_idt &name, irept &irep);
426
427 bool operator==(const irept &other) const;
428
429 bool operator!=(const irept &other) const
430 {
431 return !(*this==other);
432 }
433
434 void swap(irept &irep)
435 {
436 std::swap(irep.data, data);
437 }
438
439 bool operator<(const irept &other) const;
440 bool ordering(const irept &other) const;
441
442 int compare(const irept &i) const;
443
444 void clear() { *this=irept(); }
445
446 void make_nil() { *this=get_nil_irep(); }
447
448 subt &get_sub() { return write().sub; } // DANGEROUS
449 const subt &get_sub() const { return read().sub; }
450 named_subt &get_named_sub() { return write().named_sub; } // DANGEROUS
451 const named_subt &get_named_sub() const { return read().named_sub; }
452
453 std::size_t hash() const;
454 std::size_t full_hash() const;
455
456 bool full_eq(const irept &other) const;
457
458 std::string pretty(unsigned indent=0, unsigned max_indent=0) const;
459
460 static bool is_comment(const irep_idt &name)
461 { return !name.empty() && name[0]=='#'; }
462
464 static std::size_t number_of_non_comments(const named_subt &);
465};
466
467// NOLINTNEXTLINE(readability/identifiers)
469{
470 std::size_t operator()(const irept &irep) const
471 {
472 return irep.hash();
473 }
474};
475
476// NOLINTNEXTLINE(readability/identifiers)
478{
479 std::size_t operator()(const irept &irep) const
480 {
481 return irep.full_hash();
482 }
483};
484
485// NOLINTNEXTLINE(readability/identifiers)
487{
488 bool operator()(const irept &i1, const irept &i2) const
489 {
490 return i1.full_eq(i2);
491 }
492};
493
495{
496 const irept &irep;
497 explicit irep_pretty_diagnosticst(const irept &irep);
498};
499
500template <>
502{
503 static std::string diagnostics_as_string(const irep_pretty_diagnosticst &irep)
504 {
505 return irep.irep.pretty();
506 }
507};
508
509template <typename derivedt, typename named_subtreest>
511{
512#ifdef IREP_DEBUG
513 std::cout << "DETACH1: " << data << '\n';
514#endif
515
516 if(data == &empty_d)
517 {
518 data = new dt;
519
520#ifdef IREP_DEBUG
521 std::cout << "ALLOCATED " << data << '\n';
522#endif
523 }
524 else if(data->ref_count > 1)
525 {
526 dt *old_data(data);
527 data = new dt(*old_data);
528
529#ifdef IREP_DEBUG
530 std::cout << "ALLOCATED " << data << '\n';
531#endif
532
533 data->ref_count = 1;
534 remove_ref(old_data);
535 }
536
537 POSTCONDITION(data->ref_count == 1);
538
539#ifdef IREP_DEBUG
540 std::cout << "DETACH2: " << data << '\n';
541#endif
542}
543
544template <typename derivedt, typename named_subtreest>
546{
547 if(old_data == &empty_d)
548 return;
549
550#if 0
551 nonrecursive_destructor(old_data);
552#else
553
554 PRECONDITION(old_data->ref_count != 0);
555
556#ifdef IREP_DEBUG
557 std::cout << "R: " << old_data << " " << old_data->ref_count << '\n';
558#endif
559
560 old_data->ref_count--;
561 if(old_data->ref_count == 0)
562 {
563#ifdef IREP_DEBUG
564 std::cout << "D: " << pretty() << '\n';
565 std::cout << "DELETING " << old_data->data << " " << old_data << '\n';
566 old_data->clear();
567 std::cout << "DEALLOCATING " << old_data << "\n";
568#endif
569
570 // may cause recursive call
571 delete old_data;
572
573#ifdef IREP_DEBUG
574 std::cout << "DONE\n";
575#endif
576 }
577#endif
578}
579
582template <typename derivedt, typename named_subtreest>
584 dt *old_data)
585{
586 std::vector<dt *> stack(1, old_data);
587
588 while(!stack.empty())
589 {
590 dt *d = stack.back();
591 stack.erase(--stack.end());
592 if(d == &empty_d)
593 continue;
594
595 INVARIANT(d->ref_count != 0, "All contents of the stack must be in use");
596 d->ref_count--;
597
598 if(d->ref_count == 0)
599 {
600 stack.reserve(
601 stack.size() + std::distance(d->named_sub.begin(), d->named_sub.end()) +
602 d->sub.size());
603
604 for(typename named_subt::iterator it = d->named_sub.begin();
605 it != d->named_sub.end();
606 it++)
607 {
608 stack.push_back(it->second.data);
609 it->second.data = &empty_d;
610 }
611
612 for(typename subt::iterator it = d->sub.begin(); it != d->sub.end(); it++)
613 {
614 stack.push_back(it->data);
615 it->data = &empty_d;
616 }
617
618 // now delete, won't do recursion
619 delete d;
620 }
621 }
622}
623
624#endif // CPROVER_UTIL_IREP_H
virtual void clear()
Reset the abstract state.
Definition ai.h:265
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
ait()
Definition ai.h:565
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:364
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
void set(const irep_idt &name, irept irep)
Definition irep.h:416
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:429
const subt & get_sub() const
Definition irep.h:449
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 irep_idt & get(const irep_idt &name) const
Definition irep.cpp:44
irept(const irep_idt &_id)
Definition irep.h:377
void remove(const irep_idt &name)
Definition irep.cpp:87
void set(const irep_idt &name, const irep_idt &value)
Definition irep.h:412
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:381
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:444
bool is_not_nil() const
Definition irep.h:372
const named_subt & get_named_sub() const
Definition irep.h:451
const std::string & id_string() const
Definition irep.h:391
bool operator<(const irept &other) const
defines ordering on the internal representation
Definition irep.cpp:395
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
subt & get_sub()
Definition irep.h:448
std::size_t full_hash() const
Definition irep.cpp:453
void make_nil()
Definition irep.h:446
signed int get_int(const irep_idt &name) const
Definition irep.cpp:62
static bool is_comment(const irep_idt &name)
Definition irep.h:460
void move_to_sub(irept &irep)
Definition irep.cpp:35
void swap(irept &irep)
Definition irep.h:434
const irep_idt & id() const
Definition irep.h:388
void id(const irep_idt &_data)
Definition irep.h:394
irept & add(const irep_idt &name)
Definition irep.cpp:103
bool is_nil() const
Definition irep.h:368
named_subt & get_named_sub()
Definition irep.h:450
const std::string & get_string(const irep_idt &name) const
Definition irep.h:401
Base class for tree-like data structures without sharing.
Definition irep.h:263
non_sharing_treet(irep_idt _id, named_subt _named_sub, subt _sub)
Definition irep.h:276
const dt & read() const
Definition irep.h:283
non_sharing_treet()=default
typename dt::subt subt
Definition irep.h:266
non_sharing_treet(irep_idt _id)
Definition irep.h:272
typename dt::named_subt named_subt
Definition irep.h:267
dt & write()
Definition irep.h:288
Base class for tree-like data structures with sharing.
Definition irep.h:149
sharing_treet & operator=(sharing_treet &&irep)
Definition irep.h:216
sharing_treet(irep_idt _id, named_subt _named_sub, subt _sub)
Definition irep.h:162
dt * data
Definition irep.h:232
sharing_treet(irep_idt _id)
Definition irep.h:158
static void remove_ref(dt *old_data)
Definition irep.h:545
typename dt::named_subt named_subt
Definition irep.h:153
typename dt::subt subt
Definition irep.h:152
sharing_treet tree_implementationt
Used to refer to this class from derived classes.
Definition irep.h:156
sharing_treet(const sharing_treet &irep)
Definition irep.h:173
static void nonrecursive_destructor(dt *old_data)
Does the same as remove_ref, but using an explicit stack instead of recursion.
Definition irep.h:583
static dt empty_d
Definition irep.h:233
sharing_treet()
Definition irep.h:168
sharing_treet(sharing_treet &&irep)
Definition irep.h:188
const dt & read() const
Definition irep.h:240
dt & write()
Definition irep.h:245
sharing_treet & operator=(const sharing_treet &irep)
Definition irep.h:196
~sharing_treet()
Definition irep.h:226
void detach()
Definition irep.h:510
A node with data in a tree, it contains:
Definition irep.h:90
named_subt named_sub
Definition irep.h:105
named_subtreest named_subt
Definition irep.h:98
friend treet
Definition irep.h:100
tree_nodet()=default
void swap(tree_nodet &d)
Definition irep.h:122
tree_nodet(irep_idt _data, named_subt _named_sub, subt _sub)
Definition irep.h:138
std::vector< treet > subt
Definition irep.h:93
void clear()
Definition irep.h:112
tree_nodet(irep_idt _data)
Definition irep.h:134
std::size_t hash_code
Definition irep.h:109
subt sub
Definition irep.h:106
irep_idt data
This irep_idt is the only place to store data in an tree node.
Definition irep.h:103
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:44
STL namespace.
#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:503
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:488
std::size_t operator()(const irept &irep) const
Definition irep.h:479
std::size_t operator()(const irept &irep) const
Definition irep.h:470
const irept & irep
Definition irep.h:496
Used in tree_nodet for activating or not reference counting.
Definition irep.h:61