CBMC
reference_counting.h
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Reference Counting
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
11 
12 #ifndef CPROVER_UTIL_REFERENCE_COUNTING_H
13 #define CPROVER_UTIL_REFERENCE_COUNTING_H
14 
15 #include "invariant.h"
16 
19 template <typename T, const T &empty = T::blank>
20 // NOLINTNEXTLINE(readability/identifiers)
22 {
23 public:
24  reference_counting():d(nullptr)
25  {
26  }
27 
28  explicit reference_counting(const T &other):d(NULL)
29  {
30  write()=other;
31  }
32 
33  // copy constructor
35  {
36  if(d!=nullptr)
37  {
38  PRECONDITION(d->ref_count != 0);
39  d->ref_count++;
40  #ifdef REFERENCE_COUNTING_DEBUG
41  std::cout << "COPY " << d << " " << d->ref_count << '\n';
42  #endif
43  }
44  }
45 
47  {
48  copy_from(other);
49  return *this;
50  }
51 
53  {
54  remove_ref(d);
55  d=nullptr;
56  }
57 
58  void swap(reference_counting &other)
59  {
60  std::swap(other.d, d);
61  }
62 
63  void clear()
64  {
65  remove_ref(d);
66  d=nullptr;
67  }
68 
69  const T &read() const
70  {
71  if(d==nullptr)
72  return empty;
73  return *d;
74  }
75 
76  T &write()
77  {
78  detach();
79  return *d;
80  }
81 
82 protected:
83  class dt:public T
84  {
85  public:
86  unsigned ref_count;
87 
89  {
90  }
91  };
92 
93  dt *d;
94 
95  void remove_ref(dt *old_d);
96 
97  void detach();
98 
99  void copy_from(const reference_counting &other)
100  {
101  PRECONDITION(&other != this); // check if we assign to ourselves
102 
103  #ifdef REFERENCE_COUNTING_DEBUG
104  std::cout << "COPY " << (&other) << "\n";
105  #endif
106 
107  remove_ref(d);
108  d=other.d;
109  if(d!=nullptr)
110  d->ref_count++;
111  }
112 
113 public:
114  dt *get_d() const
115  {
116  return d;
117  }
118 };
119 
120 template <class T, const T &empty>
122 {
123  if(old_d==nullptr)
124  return;
125 
126  PRECONDITION(old_d->ref_count != 0);
127 
128  #ifdef REFERENCE_COUNTING_DEBUG
129  std::cout << "R: " << old_d << " " << old_d->ref_count << '\n';
130  #endif
131 
132  old_d->ref_count--;
133  if(old_d->ref_count==0)
134  {
135  #ifdef REFERENCE_COUNTING_DEBUG
136  std::cout << "DELETING " << old_d << '\n';
137  old_d->clear();
138  std::cout << "DEALLOCATING " << old_d << "\n";
139  #endif
140 
141  delete old_d;
142 
143  #ifdef REFERENCE_COUNTING_DEBUG
144  std::cout << "DONE\n";
145  #endif
146  }
147 }
148 
149 template <class T, const T &empty>
151 {
152  #ifdef REFERENCE_COUNTING_DEBUG
153  std::cout << "DETACH1: " << d << '\n';
154  #endif
155 
156  if(d==nullptr)
157  {
158  d=new dt;
159 
160  #ifdef REFERENCE_COUNTING_DEBUG
161  std::cout << "ALLOCATED " << d << '\n';
162  #endif
163  }
164  else if(d->ref_count>1)
165  {
166  dt *old_d(d);
167  d=new dt(*old_d);
168 
169  #ifdef REFERENCE_COUNTING_DEBUG
170  std::cout << "ALLOCATED " << d << '\n';
171  #endif
172 
173  d->ref_count=1;
174  remove_ref(old_d);
175  }
176 
177  POSTCONDITION(d->ref_count == 1);
178 
179  #ifdef REFERENCE_COUNTING_DEBUG
180  std::cout << "DETACH2: " << d << '\n'
181  #endif
182 }
183 
184 template <class T, const T &empty>
188 {
189  if(o1.get_d()==o2.get_d())
190  return true;
191  return o1.read()==o2.read();
192 }
193 
194 template <class T, const T &empty>
195 inline bool operator!=(
198 { return !(i1==i2); }
199 
200 #endif // CPROVER_UTIL_REFERENCE_COUNTING_H
reference_counting(const T &other)
void remove_ref(dt *old_d)
reference_counting & operator=(const reference_counting &other)
const T & read() const
void swap(reference_counting &other)
reference_counting(const reference_counting &other)
void copy_from(const reference_counting &other)
bool operator==(const reference_counting< T, empty > &o1, const reference_counting< T, empty > &o2)
bool operator!=(const reference_counting< T, empty > &i1, const reference_counting< T, empty > &i2)
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
#define POSTCONDITION(CONDITION)
Definition: invariant.h:479